class Simulador():
    SADIO = 0
    INFECTADO_TIPO_1 = 1  #assintomáticos e o infectado inicial
    INFECTADO_TIPO_2 = 2  #sintomático
    CURADO = 3
    MORTO = 4

    def __init__(
        self,
        tamanho_matriz,  #numero de linhas e colunas da matriz esférica
        percentual_inicial_tipo1,  #percentual inicial da população que será infectada tipo 1
        percentual_inicial_tipo2,  #percentual inicial da população que será infectada tipo 2
        chance_infeccao,  #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,  #chance de um indivíduo infectado se tornar contagioso
        chance_morte,  #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura
    ):  #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2

        self.num_atualizacoes = 0
        self.lista_infectados_tipo_2 = []
        self.lista_infectados_tipo_1 = []
        self.num_curados = 0
        self.num_mortos = 0

        self.chance_infeccao = chance_infeccao
        self.chance_infeccao_tipo2 = chance_infeccao_tipo2
        self.chance_morte = chance_morte
        self.atualizacoes_cura = atualizacoes_cura

        self.populacao_inicial = int(tamanho_matriz**2)
        self.num_inicial_tipo2 = int(self.populacao_inicial *
                                     percentual_inicial_tipo2)
        self.num_inicial_tipo1 = 1 + int(
            self.populacao_inicial * percentual_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (
            self.num_inicial_tipo2 + self.num_inicial_tipo1)

        self.matriz_status = lil_matrix(
            (tamanho_matriz, tamanho_matriz), dtype=np.uint8
        )  # np.zeros((tamanho_matriz, tamanho_matriz),dtype= np.uint8)#
        self.matriz_atualizacoes_cura = lil_matrix(
            (tamanho_matriz, tamanho_matriz), dtype=np.uint8
        )  #np.zeros((tamanho_matriz, tamanho_matriz),dtype= np.uint8)#

        #self.matriz_status = self.df_individuos.to_numpy()
        self.popular(tamanho_matriz)

        self.lista_matrizes_status = []

        #objeto que é responsável por validar a movimentação no grid n x n
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        dict = {
            'num_sadios': self.num_inicial_sadios,
            'num_infect_t1': self.num_inicial_tipo1,
            'num_infect_t2': self.num_inicial_tipo2,
            'num_curados': 0,
            'num_mortos': 0
        }

        #dataframe que guardará os resultados de cada atualização
        self.dataframe = pd.DataFrame(dict, index=[0])
        self.salvar_posicionamento()

    def criar_individuo(self, status, posicao):

        self.matriz_status[posicao[0], posicao[1]] = status
        if status == self.INFECTADO_TIPO_1 or status == self.INFECTADO_TIPO_2:
            self.matriz_atualizacoes_cura[posicao[0],
                                          posicao[1]] = self.atualizacoes_cura
        else:
            self.matriz_atualizacoes_cura[posicao[0], posicao[1]] = 0

    def salvar_posicionamento(self):

        self.lista_matrizes_status.append(self.matriz_status)

    def verificar_infeccao(self, lista_infectantes):
        lista_novos_infectados_tipo1 = []
        lista_novos_infectados_tipo2 = []
        #itera sobre sobre a lista de individuos que infectam e cada um realiza a tividade de infectar
        for indice_infectante in lista_infectantes:

            #busca os vizinhos do infectante atual
            lista_vizinhos = self.matriz_esferica.get_vizinhos(
                indice_infectante)

            #Para cada vizinho, se ele for sadio, é gerado um número aleatório para verificar se foi infectado
            for indice_vizinho in lista_vizinhos:

                #verificação de SADIO
                if self.verifica_status(indice_vizinho) == self.SADIO:
                    #verificação do novo status
                    novo_status = self.infectar(chance_infeccao,
                                                chance_infeccao_tipo2)
                    #se for um infectado tipo 1
                    if novo_status == Individuo.INFECTADO_TIPO_1:
                        #adiciona na lista de novos tipo 1
                        lista_novos_infectados_tipo1.append(indice_vizinho)
                    if novo_status == Individuo.INFECTADO_TIPO_2:
                        #adiciona na lista de novos tipo 2
                        lista_novos_infectados_tipo2.append(indice_vizinho)

        return lista_novos_infectados_tipo1, lista_novos_infectados_tipo2

    def checagem_morte_individual(self, chance_morte):
        rng_morte = random.random()
        if rng_morte <= chance_morte:

            return self.MORTO
        else:
            return self.INFECTADO_TIPO_2

    def checar_cura_individual(self, indice):

        self.matriz_atualizacoes_cura[
            indice[0],
            indice[1]] = self.matriz_atualizacoes_cura[indice[0],
                                                       indice[1]] - 1
        if self.matriz_atualizacoes_cura[indice[0], indice[1]] == 0:
            return self.CURADO
        else:
            return self.matriz_status[indice[0], indice[1]]

    def checagem_morte_lista(self, lista_infectantes):
        lista_mortos = []
        for indice_infectante in lista_infectantes:
            novo_status = self.checagem_morte_individual(self.chance_morte)
            if novo_status == Individuo.MORTO:
                lista_mortos.append(indice_infectante)
        return lista_mortos

    def checagem_cura_lista(self, lista_infectantes):
        lista_curados = []
        for indice_infectante in lista_infectantes:
            novo_status = self.checar_cura_individual(indice_infectante)
            if novo_status == Individuo.CURADO:
                lista_curados.append(indice_infectante)

        return lista_curados

    def iterar(self):

        #Verifica os novos infectados por infectantes do tipo 1 e 2
        #print(self.lista_infectados_tipo_1+self.lista_infectados_tipo_2)
        lista_novos_infectados_tipo1, lista_novos_infectados_tipo2 = self.verificar_infeccao(
            self.lista_infectados_tipo_1 + self.lista_infectados_tipo_2)

        for indice in lista_novos_infectados_tipo1:
            self.criar_individuo(self.INFECTADO_TIPO_1, indice)
        for indice in lista_novos_infectados_tipo2:
            self.criar_individuo(self.INFECTADO_TIPO_2, indice)

        #Verifica morte dos infectados tipo 2
        lista_mortos = self.checagem_morte_lista(self.lista_infectados_tipo_2)
        #retira os indices dos individuos mortos da lista de infectados
        self.lista_infectados_tipo_2 = [
            indice for indice in self.lista_infectados_tipo_2
            if indice not in lista_mortos
        ]
        #Instancia individuos mortos na matriz
        for indice in lista_mortos:
            self.criar_individuo(self.MORTO, indice)
        #atualiza o número de mortos na matriz
        self.num_mortos = self.num_mortos + len(lista_mortos)

        #Verifica cura dos infectados tipo 1
        lista_curados_t1 = self.checagem_cura_lista(
            self.lista_infectados_tipo_1)

        #Verifica cura dos infectados tipo 2
        lista_curados_t2 = self.checagem_cura_lista(
            self.lista_infectados_tipo_2)

        #Instancia individuos mortos na matriz
        for indice in lista_curados_t1 + lista_curados_t2:
            self.criar_individuo(self.CURADO, indice)

        #atualiza o número de curados na matriz
        self.num_curados = self.num_curados + len(lista_curados_t1 +
                                                  lista_curados_t2)

        #Atualiza a lista de infectados após a cura dos individuos
        self.lista_infectados_tipo_1 = [
            indice for indice in self.lista_infectados_tipo_1
            if indice not in lista_curados_t1
        ]
        self.lista_infectados_tipo_2 = [
            indice for indice in self.lista_infectados_tipo_2
            if indice not in lista_curados_t2
        ]

        #movimentação
        nova_lista_t1 = []
        for indice in self.lista_infectados_tipo_1:
            nova_lista_t1.append(self.mover_infectante(indice))
        self.lista_infectados_tipo_1 = nova_lista_t1

        nova_lista_t2 = []
        for indice in self.lista_infectados_tipo_2:
            nova_lista_t2.append(self.mover_infectante(indice))
        self.lista_infectados_tipo_2 = nova_lista_t2

        matriz_infectantes = self.matriz_status[
            (self.matriz_status == self.INFECTADO_TIPO_1) +
            (self.matriz_status == self.INFECTADO_TIPO_2)]
        # matriz_infectantes = matriz_infectantes[matriz_infectantes < 3]
        indices_infectados = list(zip(*self.matriz_status.nonzero()))
        #indices_infectados = [indice in indices_infectados if indice not in self.lista_infectados_tipo_1 and indice not in self.lista_infectados_tipo_1 ]
        # self.num_curados = 0
        #self.num_mortos = 0
        novos_infectados_tipo_1 = []
        novos_infectados_tipo_2 = []
        for indice in indices_nao_sadios:

            status = self.matriz_status[indice[0], indice[1]]
            if status == self.INFECTADO_TIPO_1:
                novos_infectados_tipo_1.append(indice)
                # self.lista_infectados_tipo_1.append(indice)
            if status == self.INFECTADO_TIPO_2:
                novos_infectados_tipo_2.append(indice)
                # self.lista_infectados_tipo_2.append(indice)
            # if status == self.CURADO:
            #     self.num_curados +=1
            # if status == self.MORTO:
            #     self.num_mortos +=1

        self.lista_infectados_tipo_1 = self.lista_infectados_tipo_1 + novos_infectados_tipo_1
        self.lista_infectados_tipo_2 = self.lista_infectados_tipo_2 + novos_infectados_tipo_1
        dict = {
            'num_sadios':
            self.populacao_inicial - len(self.lista_infectados_tipo_1) -
            len(self.lista_infectados_tipo_2) - self.num_curados -
            self.num_mortos,
            'num_infect_t1':
            len(self.lista_infectados_tipo_1),
            'num_infect_t2':
            len(self.lista_infectados_tipo_2),
            'num_curados':
            self.num_curados,
            'num_mortos':
            self.num_mortos
        }

        self.dataframe = self.dataframe.append(dict, ignore_index=True)

        self.salvar_posicionamento()

        #adiciona 1 ao número de atualizações realizadas na matriz
        self.num_atualizacoes += 1

    def infectar(self, chance_infeccao, chance_infeccao_tipo2):
        saida = Individuo.SADIO

        #número aleatório para chance de infectar o vizinho
        rng_infeccao = random.random()
        if rng_infeccao <= chance_infeccao:
            #número aleatório para chance de infecção tipo 1 ou 2
            rng_infeccao_tipo2 = random.random()
            if rng_infeccao_tipo2 <= chance_infeccao_tipo2:
                saida = Individuo.INFECTADO_TIPO_2
            else:
                saida = Individuo.INFECTADO_TIPO_1
        return saida

    def popular(self, tamanho_matriz):

        #lista de possíveis combinações de índices da matriz de dados
        permutacoes = permutations(list(range(tamanho_matriz)), 2)
        #conversão para lista de tuplas(x,y)
        lista_indices = list(permutacoes)
        #embaralhamento dos índices
        random.shuffle(lista_indices)

        #cria o primeiro tipo1:
        indice = lista_indices.pop()
        self.criar_individuo(Individuo.INFECTADO_TIPO_1, indice)
        self.lista_infectados_tipo_1.append(indice)
        #cria o restante dos tipos 1
        for i in range(self.num_inicial_tipo1 - 1):
            indice = lista_indices.pop()
            self.criar_individuo(Individuo.INFECTADO_TIPO_1, indice)
            self.lista_infectados_tipo_1.append(indice)
        #cria o restante dos tipo 2:
        for indice in range(self.num_inicial_tipo2):
            indice = lista_indices.pop()
            self.criar_individuo(Individuo.INFECTADO_TIPO_2, indice)
            self.lista_infectados_tipo_2.append(indice)

    def trocar(self, matriz, ponto_ini, ponto_final):
        x_ini = ponto_ini[0]
        y_ini = ponto_ini[1]
        x_fin = ponto_final[0]
        y_fin = ponto_final[1]

        aux = matriz[x_fin, y_fin]
        matriz[x_fin, y_fin] = matriz[x_ini, y_ini]
        matriz[x_ini, y_ini] = aux

    def verifica_status(self, indice):
        return self.matriz_status[indice[0], indice[1]]

    def mover_infectante(self, posicao_inicial):
        pos_x, pos_y = posicao_inicial[0], posicao_inicial[1]
        rng_posicao = random.random()
        if rng_posicao <= 0.25:
            #move pra cima
            pos_x -= 1
        elif rng_posicao <= 0.5:
            #move pra baixo
            pos_x += 1
        elif rng_posicao <= 0.75:
            #move para esquerda
            pos_y -= 1
        else:
            #move para direita
            pos_y += 1

        posicao_final = self.matriz_esferica.valida_ponto_matriz(pos_x, pos_y)

        self.trocar(self.matriz_status, posicao_inicial, posicao_final)
        self.trocar(self.matriz_atualizacoes_cura, posicao_inicial,
                    posicao_final)
        return posicao_final
class Simulador():
    def __init__(
        self,
        tamanho_matriz,  #numero de linhas e colunas da matriz esférica
        percentual_inicial_tipo1,  #percentual inicial da população que será infectada tipo 1
        percentual_inicial_tipo2,  #percentual inicial da população que será infectada tipo 2
        chance_infeccao,  #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,  #chance de um indivíduo infectado se tornar contagioso
        chance_morte,  #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura
    ):  #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2

        self.num_atualizacoes = 0
        self.lista_infectados_tipo_2 = []
        self.lista_infectados_tipo_1 = []
        self.num_curados = 0
        self.num_mortos = 0

        self.chance_infeccao = chance_infeccao
        self.chance_infeccao_tipo2 = chance_infeccao_tipo2
        self.chance_morte = chance_morte
        self.atualizacoes_cura = atualizacoes_cura

        self.populacao_inicial = int(tamanho_matriz**2)
        self.num_inicial_tipo2 = int(self.populacao_inicial *
                                     percentual_inicial_tipo2)
        self.num_inicial_tipo1 = 1 + int(
            self.populacao_inicial * percentual_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (
            self.num_inicial_tipo2 + self.num_inicial_tipo1)

        self.df_individuos = pd.DataFrame(self.criar_individuo(
            Individuo.SADIO, (0, 0)),
                                          index=range(tamanho_matriz),
                                          columns=range(tamanho_matriz))
        self.matriz_status = lil_matrix((tamanho_matriz, tamanho_matriz),
                                        dtype=np.uint8)
        #self.matriz_status = self.df_individuos.to_numpy()
        self.popular(tamanho_matriz)

        self.lista_matrizes_posicionamento = []

        #objeto que é responsável por validar a movimentação no grid n x n
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        dict = {
            'num_sadios': self.num_inicial_sadios,
            'num_infect_t1': self.num_inicial_tipo1,
            'num_infect_t2': self.num_inicial_tipo2,
            'num_curados': 0,
            'num_mortos': 0
        }

        #dataframe que guardará os resultados de cada atualização
        self.dataframe = pd.DataFrame(dict, index=[0])
        self.salvar_posicionamento()

    def criar_individuo(self, status, posicao):

        return Individuo(status, self.atualizacoes_cura, posicao)

    def salvar_posicionamento(self):
        self.matriz_status = self.df_individuos.to_numpy()
        self.lista_matrizes_posicionamento.append(self.matriz_status)

    def verificar_infeccao(self, lista_infectantes):
        lista_novos_infectados_tipo1 = []
        lista_novos_infectados_tipo2 = []
        #itera sobre sobre a lista de individuos que infectam e cada um realiza a tividade de infectar
        print(lista_infectantes)
        for X, Y in lista_infectantes:

            print("Infectante na posição: ", (X, Y))
            #busca os vizinhos do infectante atual
            lista_vizinhos = self.matriz_esferica.get_vizinhos(X, Y)
            print("Lista vizinhos: ", lista_vizinhos)
            #Para cada vizinho, se ele for sadio, é gerado um número aleatório para verificar se foi infectado
            for x, y in lista_vizinhos:
                print("posição vizinho: ", (x, y))
                print("tipo de individuo ", type(self.df_individuos.iloc[x,
                                                                         y]))
                #verificação de SADIO
                if self.df_individuos[x][y].status == Individuo.SADIO:
                    #verificação do novo status
                    novo_status = self.infectar(chance_infeccao,
                                                chance_infeccao_tipo2)
                    #se for um infectado tipo 1
                    if novo_status == Individuo.INFECTADO_TIPO_1:
                        #adiciona na lista de novos tipo 1
                        lista_novos_infectados_tipo1.append((x, y))
                        #modifica o status na matriz de status
                        print(
                            "Tipo antes de atribuir: ",
                            self.criar_individuo(Individuo.INFECTADO_TIPO_1,
                                                 (x, y)))
                        self.df_individuos.iloc[x, y] = self.criar_individuo(
                            Individuo.INFECTADO_TIPO_1, (x, y))
                        print("Tipo depois de atribuir: ",
                              self.df_individuos.loc[x, y])
                        self.matriz_status[x, y] = Individuo.INFECTADO_TIPO_1

                    if novo_status == Individuo.INFECTADO_TIPO_2:
                        #adiciona na lista de novos tipo 2
                        lista_novos_infectados_tipo2.append((x, y))
                        #modifica o status na matriz de status
                        self.df_individuos.iloc[x, y] = self.criar_individuo(
                            Individuo.INFECTADO_TIPO_2, (x, y))
                        self.matriz_status[x, y] = Individuo.INFECTADO_TIPO_2
                print(self.df_individuos)
        return lista_novos_infectados_tipo1, lista_novos_infectados_tipo2

    def verificar_morte(self, lista_infectantes_tipo2):
        lista_curados = []
        lista_mortos = []
        for x, y in lista_infectantes_tipo2:
            novo_status = self.df_individuos.loc[x, y].checagem_morte(
                self.chance_morte)
            if novo_status == Individuo.MORTO:

                self.matriz_status[x, y] = Individuo.MORTO
                lista_mortos.append((x, y))
            if novo_status == Individuo.CURADO:

                self.matriz_status[x, y] = Individuo.CURADO
                lista_curados.append((x, y))

        return lista_mortos, lista_curados

    def verificar_cura(self, lista_infectantes):
        lista_curados = []
        for x, y in lista_infectantes:
            print("AQUI======>: ", self.df_individuos.loc[x, y])
            novo_status = self.df_individuos.loc[x, y].checagem_cura()
            if novo_status == Individuo.CURADO:

                self.matriz_status[x, y] = Individuo.CURADO
                lista_curados.append((x, y))

        return lista_curados

    def iterar(self):

        #Verifica os novos infectados a partir dos atuais infectantes na matriz
        lista_novos_infectados_tipo1, lista_novos_infectados_tipo2 = self.verificar_infeccao(
            self.lista_infectados_tipo_1)
        lista_novos_infectados_tipo1, lista_novos_infectados_tipo2 = self.verificar_infeccao(
            self.lista_infectados_tipo_2)

        #Verifica morte dos tipo 2
        lista_mortos_atualizacao, lista_curados_t2_atualizacao = self.verificar_morte(
            self.lista_infectados_tipo_2)

        self.lista_infectados_tipo_2 = [
            indice for indice in self.lista_infectados_tipo_2
            if indice not in lista_mortos_atualizacao
            and indice not in lista_curados_t2_atualizacao
        ]

        #atualiza o novo número de mortos
        self.num_mortos += len(lista_mortos_atualizacao)
        #Verificar cura
        lista_curados_t1_atualizacao = self.verificar_cura(
            self.lista_infectados_tipo_1)
        self.lista_infectados_tipo_1 = [
            indice for indice in self.lista_infectados_tipo_1
            if indice not in lista_curados_t1_atualizacao
        ]
        #adiciona os novos curados na lista geral de curados
        self.num_curados = self.num_curados + len(
            lista_curados_t1_atualizacao) + len(lista_curados_t2_atualizacao)

        # self.  #movimentar infectantes:
        # for x,y in self.lista_infectados_tipo_1:
        #     self.mover_infectante((x,y))

        # for x,y in self.lista_infectados_tipo_2:
        #     self.mover_infectante((x,y))

        #adicionar os novos infectados tipo 1 e 2 para as respectivas listas
        self.lista_infectados_tipo_2 = self.lista_infectados_tipo_2 + lista_novos_infectados_tipo2
        self.lista_infectados_tipo_1 = self.lista_infectados_tipo_1 + lista_novos_infectados_tipo1

        dict = {
            'num_sadios':
            self.populacao_inicial - self.num_mortos - self.num_curados -
            len(self.lista_infectados_tipo_1) -
            len(self.lista_infectados_tipo_2),
            'num_infect_t1':
            len(self.lista_infectados_tipo_1),
            'num_infect_t2':
            len(self.lista_infectados_tipo_2),
            'num_curados':
            self.num_curados,
            'num_mortos':
            self.num_mortos
        }

        self.dataframe = self.dataframe.append(dict, ignore_index=True)

        print("num t1: ", len(self.lista_infectados_tipo_1))
        print("num t2: ", len(self.lista_infectados_tipo_2))
        print("num curados: ", self.num_curados)
        print("num mortos: ", self.num_mortos)
        print("---------")
        #salva a nova matriz de status
        self.salvar_posicionamento()

        #adiciona 1 ao número de atualizações realizadas na matriz
        self.num_atualizacoes += 1

    def infectar(self, chance_infeccao, chance_infeccao_tipo2):
        saida = Individuo.SADIO

        #número aleatório para chance de infectar o vizinho
        rng_infeccao = random.random()
        if rng_infeccao <= chance_infeccao:
            #número aleatório para chance de infecção tipo 1 ou 2
            rng_infeccao_tipo2 = random.random()
            if rng_infeccao_tipo2 <= chance_infeccao_tipo2:
                saida = Individuo.INFECTADO_TIPO_2
            else:
                saida = Individuo.INFECTADO_TIPO_1
        return saida

    def popular(self, tamanho_matriz):

        #self.df_individuos.iloc[:,:] = self.criar_individuo(Individuo.SADIO,(0,0))

        #lista de possíveis combinações de índices da matriz de dados
        permutacoes = permutations(list(range(tamanho_matriz)), 2)
        #conversão para lista de tuplas(x,y)
        lista_indices = list(permutacoes)
        #embaralhamento dos índices
        random.shuffle(lista_indices)

        #cria o primeiro tipo1:
        indice = lista_indices.pop()
        ind_x = indice[0]
        ind_y = indice[1]
        self.lista_infectados_tipo_1.append((ind_x, ind_y))
        #print(indice)
        self.df_individuos.loc[ind_x, ind_y] = self.criar_individuo(
            Individuo.INFECTADO_TIPO_1, (ind_x, ind_y))
        #print(self.df_individuos)
        self.matriz_status[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
        #cria o restante dos tipos 1
        for i in range(1, self.num_inicial_tipo1):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.lista_infectados_tipo_1.append((ind_x, ind_y))
            self.df_individuos.loc[ind_x, ind_y] = self.criar_individuo(
                Individuo.INFECTADO_TIPO_1, (ind_x, ind_y))
            self.matriz_status[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1

        #cria o restante dos tipo 2:
        for indice in range(self.num_inicial_tipo2):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.lista_infectados_tipo_2.append((ind_x, ind_y))
            self.df_individuos.loc[
                ind_x, ind_y] = self.fabrica_individuo.criar_individuo(
                    Individuo.INFECTADO_TIPO_2, (ind_x, ind_y))
            self.matriz_status[ind_x, ind_y] = Individuo.INFECTADO_TIPO_2

    def trocar_status_localizacao(self, ponto_ini, ponto_final):
        x_ini = ponto_ini[0]
        y_ini = ponto_ini[1]
        x_fin = ponto_final[0]
        y_fin = ponto_final[1]

        aux = self.df_individuos.loc[x_fin, y_fin]
        print("Aux2====>: ", self.df_individuos.loc[x_fin, y_fin])
        self.df_individuos.loc[x_fin, y_fin], self.df_individuos.loc[
            x_ini, y_ini] = self.df_individuos.loc[
                x_ini, y_ini], self.df_individuos.loc[x_fin, y_fin]
        # self.df_individuos.loc[x_fin,y_fin] = self.df_individuos.loc[x_ini,y_ini]
        # self.df_individuos.loc[x_ini,y_ini] = aux2

        self.matriz_status[x_fin, y_fin] = self.df_individuos.loc[x_fin,
                                                                  y_fin].status
        self.matriz_status[x_ini, y_ini] = self.df_individuos.loc[x_ini,
                                                                  y_ini].status

    def mover_infectante(self, posicao_inicial):
        pos_x, pos_y = posicao_inicial[0], posicao_inicial[1]
        rng_posicao = random.random()
        if rng_posicao <= 0.25:
            #move pra cima
            pos_x -= 1
        elif rng_posicao <= 0.5:
            #move pra baixo
            pos_x += 1
        elif rng_posicao <= 0.75:
            #move para esquerda
            pos_y -= 1
        else:
            #move para direita
            pos_y += 1

        posicao_final = self.matriz_esferica.valida_ponto_matriz(pos_x, pos_y)

        self.trocar_status_localizacao(posicao_inicial, posicao_final)
Ejemplo n.º 3
0
    def __init__(
        self,
        tamanho_matriz,  #numero de linhas e colunas da matriz esférica
        chance_infeccao,  #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,  #chance de um indivíduo infectado se tornar contagioso
        chance_morte,  #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura,  #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2
        inserir_infectados_aleatorios):
        self.num_atualizacoes = 0
        self.lista_infectados_tipo_2 = []
        self.lista_infectados_tipo_1 = []
        self.num_curados = 0
        self.num_mortos = 0

        self.chance_infeccao = chance_infeccao
        self.chance_infeccao_tipo2 = chance_infeccao_tipo2
        self.chance_morte = chance_morte
        self.atualizacoes_cura = atualizacoes_cura

        self.populacao_inicial = int(tamanho_matriz**2)

        num_inicial_infectados = random.randint(
            0, tamanho_matriz * tamanho_matriz - 1)

        proporcao_t1_t2 = random.random()

        self.num_inicial_tipo1 = round(inserir_infectados_aleatorios *
                                       proporcao_t1_t2 *
                                       num_inicial_infectados)
        print("self.num_inicial_tipo1: ", self.num_inicial_tipo1)
        self.num_inicial_tipo2 = round(inserir_infectados_aleatorios *
                                       (1 - proporcao_t1_t2) *
                                       num_inicial_infectados)
        print("self.num_inicial_tipo2: ", self.num_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (
            self.num_inicial_tipo2 + self.num_inicial_tipo1)

        self.matriz_status = np.zeros(
            (tamanho_matriz, tamanho_matriz), dtype=np.uint8
        )  #lil_matrix((tamanho_matriz, tamanho_matriz),dtype= np.uint8) #
        self.matriz_atualizacoes_cura = np.zeros(
            (tamanho_matriz, tamanho_matriz), dtype=np.uint8
        )  #lil_matrix((tamanho_matriz, tamanho_matriz),dtype= np.uint8)#

        self.dict_resumo = {}

        #self.matriz_status = self.df_individuos.to_numpy()
        self.popular(tamanho_matriz)

        self.lista_matrizes_status = []

        #objeto que é responsável por validar a movimentação no grid n x n
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        dict = {
            'num_sadios': self.num_inicial_sadios,
            'num_infect_t1': self.num_inicial_tipo1,
            'num_infect_t2': self.num_inicial_tipo2,
            'num_curados': 0,
            'num_mortos': 0
        }

        #dataframe que guardará os resultados de cada atualização
        self.dataframe = pd.DataFrame(dict, index=[0])
        self.salvar_posicionamento()
Ejemplo n.º 4
0
class Simulador():
    def __init__(
        self,
        tamanho_matriz,  #numero de linhas e colunas da matriz esférica
        percentual_inicial_tipo1,  #percentual inicial da população que será infectada tipo 1
        percentual_inicial_tipo2,  #percentual inicial da população que será infectada tipo 2
        chance_infeccao,  #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,  #chance de um indivíduo infectado se tornar contagioso
        chance_morte,  #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura
    ):  #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2

        self.num_atualizacoes = 0
        self.lista_infectados_tipo_2 = []
        self.lista_infectados_tipo_1 = []
        self.num_curados = 0
        self.num_mortos = 0

        self.chance_infeccao = chance_infeccao
        self.chance_infeccao_tipo2 = chance_infeccao_tipo2
        self.chance_morte = chance_morte

        self.populacao_inicial = int(tamanho_matriz**2)
        self.num_inicial_tipo2 = int(self.populacao_inicial *
                                     percentual_inicial_tipo2)
        self.num_inicial_tipo1 = int(self.populacao_inicial *
                                     percentual_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (
            self.num_inicial_tipo2 + self.num_inicial_tipo1)
        self.fabrica_individuo = Fabrica_individuo(atualizacoes_cura)

        self.df_individuos = pd.DataFrame(index=range(tamanho_matriz),
                                          columns=range(tamanho_matriz))

        self.popular(tamanho_matriz)

        self.lista_matrizes_posicionamento = []

        #objeto que é responsável por validar a movimentação no grid n x n
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        self.matriz_status = lil_matrix((tamanho_matriz, tamanho_matriz),
                                        dtype=np.uint8)

        dict = {
            'num_sadios': self.num_inicial_sadios,
            'num_infect_t1': self.num_inicial_tipo1,
            'num_infect_t2': self.num_inicial_tipo2,
            'num_curados': 0,
            'num_mortos': 0
        }

        #dataframe que guardará os resultados de cada atualização
        self.dataframe = pd.DataFrame(index=[0])
        self.salvar_posicionamento()

    def salvar_posicionamento(self):
        self.lista_matrizes_posicionamento.append(self.matriz_status)

    def verificar_infeccao(self, lista_infectantes):
        lista_novos_infectados_tipo1 = []
        lista_novos_infectados_tipo2 = []
        #itera sobre sobre a lista de individuos que infectam e cada um realiza a tividade de infectar
        for X, Y in lista_infectantes:

            #busca os vizinhos do infectante atual
            lista_vizinhos = self.matriz_esferica.get_vizinhos(X, Y)
            #Para cada vizinho, se ele for sadio, é gerado um número aleatório para verificar se foi infectado
            for x, y in lista_vizinhos:

                #verificação de SADIO
                if self.matriz_status[x, y] == Individuo.SADIO:
                    #verificação do novo status
                    novo_status = self.infectar(chance_infeccao,
                                                chance_infeccao_tipo2)
                    #se for um infectado tipo 1
                    if novo_status == Individuo.INFECTADO_TIPO_1:
                        #adiciona na lista de novos tipo 1
                        lista_novos_infectados_tipo1.append((x, y))
                        #modifica o status na matriz de status
                        self.df_individuos.loc[
                            x, y] = self.fabrica_individuo.criar_individuo(
                                Individuo.INFECTADO_TIPO_1, (x, y))
                        self.matriz_status[x, y] = Individuo.INFECTADO_TIPO_1

                    if novo_status == Individuo.INFECTADO_TIPO_2:
                        #adiciona na lista de novos tipo 2
                        lista_novos_infectados_tipo2.append((x, y))
                        #modifica o status na matriz de status
                        self.df_individuos.loc[
                            x, y] = self.fabrica_individuo.criar_individuo(
                                Individuo.INFECTADO_TIPO_2, (x, y))
                        self.matriz_status[x, y] = Individuo.INFECTADO_TIPO_2

        return lista_novos_infectados_tipo1, lista_novos_infectados_tipo2

    def verificar_morte(self, lista_infectantes_tipo2):
        num_mortos = 0
        num_curados = 0
        for x, y in lista_infectantes_tipo2:
            novo_status = self.df_individuos.loc[x, y].checagem_morte(
                self.chance_morte)
            if novo_status == Individuo.MORTO:
                num_mortos += 1
                self.matriz_status[x, y] = Individuo.MORTO
                lista_infectantes_tipo2.remove((x, y))
            if novo_status == Individuo.CURADO:
                num_curados += 1
                self.matriz_status[x, y] = Individuo.CURADO
                lista_infectantes_tipo2.remove((x, y))

        return num_mortos, num_curados

    def verificar_cura(self, lista_infectantes):
        num_curados = 0
        for x, y in lista_infectantes:
            novo_status = self.df_individuos.loc[x, y].checagem_cura()
            if novo_status == Individuo.CURADO:
                num_curados += 1
                self.matriz_status[x, y] = Individuo.CURADO
                lista_infectantes.remove((x, y))

        return num_curados

    def iterar(self):

        #Verifica os novos infectados a partir dos atuais infectantes na matriz
        lista_novos_infectados_tipo1, lista_novos_infectados_tipo2 = self.verificar_infeccao(
            self.lista_infectados_tipo_1 + self.lista_infectados_tipo_2)

        #Verifica morte dos tipo 2
        num_mortos_atualizacao, num_curados_t2_atualizacao = self.verificar_morte(
            self.lista_infectados_tipo_2)

        # #retirar os mortos da atualização da lista de infectados tipo 2
        # self.lista_infectados_tipo_2 = [i for i in self.lista_infectados_tipo_2 if i.status != Individuo.MORTO]

        #atualiza o novo número de mortos
        self.num_mortos += num_mortos_atualizacao

        #Verificar cura
        num_curados_t1_atualizacao = self.verificar_cura(
            self.lista_infectados_tipo_1)

        # #retirar os curados das lista de infectados tipo 1 e 2
        # self.lista_infectados_tipo_2 = [i for i in self.lista_infectados_tipo_2 if i.status != Individuo.CURADO]
        # self.lista_infectados_tipo_1 = [i for i in self.lista_infectados_tipo_1 if i.status != Individuo.CURADO]

        #adiciona os novos curados na lista geral de curados
        self.num_curados = self.num_curados + num_curados_t1_atualizacao + num_curados_t2_atualizacao

        # self.  #movimentar infectantes:
        for x, y in self.lista_infectados_tipo_1:
            self.mover_infectante((x, y))

        for x, y in self.lista_infectados_tipo_2:
            self.mover_infectante((x, y))

        #adicionar os novos infectados tipo 1 e 2 para as respectivas listas
        self.lista_infectados_tipo_2 = self.lista_infectados_tipo_2 + lista_novos_infectados_tipo2
        self.lista_infectados_tipo_1 = self.lista_infectados_tipo_1 + lista_novos_infectados_tipo1

        num_tipo_1 = len(self.lista_infectados_tipo_1)

        num_tipo_2 = len(self.lista_infectados_tipo_2)

        dict = {
            'num_sadios':
            self.populacao_inicial - self.num_mortos - self.num_curados -
            num_tipo_1 - num_tipo_2,
            'num_infect_t1':
            num_tipo_1,
            'num_infect_t2':
            num_tipo_2,
            'num_curados':
            self.num_curados,
            'num_mortos':
            self.num_mortos
        }

        self.dataframe = self.dataframe.append(dict, ignore_index=True)

        print("num t1: ", num_tipo_1)
        print("num t2: ", num_tipo_2)
        print("num curados: ", self.num_curados)
        print("num mortos: ", self.num_mortos)
        print("---------")
        #salva a nova matriz de status
        self.salvar_posicionamento()

        #adiciona 1 ao número de atualizações realizadas na matriz
        self.num_atualizacoes += 1

    def infectar(self, chance_infeccao, chance_infeccao_tipo2):
        saida = Individuo.SADIO

        #número aleatório para chance de infectar o vizinho
        rng_infeccao = random.random()
        if rng_infeccao <= chance_infeccao:
            #número aleatório para chance de infecção tipo 1 ou 2
            rng_infeccao_tipo2 = random.random()
            if rng_infeccao_tipo2 <= chance_infeccao_tipo2:
                saida = Individuo.INFECTADO_TIPO_2
            else:
                saida = Individuo.INFECTADO_TIPO_1
        return saida

    def popular(self, tamanho_matriz):

        # for index, row in self.df_individuos.iterrows():
        #     for item in row:
        #         item = self.fabrica_individuo.criar_individuo(Individuo.SADIO,(0,0))
        self.df_individuos.iloc[:, :] = self.fabrica_individuo.criar_individuo(
            Individuo.SADIO, (0, 0))

        #lista de possíveis combinações de índices da matriz de dados
        permutacoes = permutations(list(range(tamanho_matriz)), 2)
        #conversão para lista de tuplas(x,y)
        lista_indices = list(permutacoes)
        #embaralhamento dos índices
        random.shuffle(lista_indices)

        #cria o primeiro tipo1:
        indice = lista_indices.pop()
        ind_x = indice[0]
        ind_y = indice[1]
        self.lista_infectados_tipo_1.append((ind_x, ind_y))
        self.df_individuos.loc[ind_x,
                               ind_y] = self.fabrica_individuo.criar_individuo(
                                   Individuo.INFECTADO_TIPO_1, (ind_x, ind_y))

        #cria o restante dos tipos 1
        for i in range(1, self.num_inicial_tipo1):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.lista_infectados_tipo_1.append((ind_x, ind_y))
            self.df_individuos.loc[
                ind_x, ind_y] = self.fabrica_individuo.criar_individuo(
                    Individuo.INFECTADO_TIPO_1, (ind_x, ind_y))

        #cria o restante dos tipo 2:
        for indice in range(self.num_inicial_tipo2):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.lista_infectados_tipo_2.append((ind_x, ind_y))
            self.df_individuos.loc[
                ind_x, ind_y] = self.fabrica_individuo.criar_individuo(
                    Individuo.INFECTADO_TIPO_2, (ind_x, ind_y))

    def trocar_status_localizacao(self, ponto_ini, ponto_final):
        x_ini = ponto_ini[0]
        y_ini = ponto_ini[1]
        x_fin = ponto_final[0]
        y_fin = ponto_final[1]

        aux1 = self.matriz_status[x_fin, y_fin]
        self.matriz_status[x_fin, y_fin] = self.matriz_status[x_ini, y_ini]
        self.matriz_status[x_ini, y_ini] = aux1

        aux2 = self.df_individuos.loc[x_fin, y_fin]
        self.df_individuos.loc[x_fin, y_fin] = self.df_individuos.loc[x_ini,
                                                                      y_ini]
        self.df_individuos.loc[x_ini, y_ini] = aux2

    def mover_infectante(self, posicao_inicial):
        pos_x, pos_y = posicao_inicial[0], posicao_inicial[1]
        rng_posicao = random.random()
        if rng_posicao <= 0.25:
            #move pra cima
            pos_x -= 1
        elif rng_posicao <= 0.5:
            #move pra baixo
            pos_x += 1
        elif rng_posicao <= 0.75:
            #move para esquerda
            pos_y -= 1
        else:
            #move para direita
            pos_y += 1

        novo_x, novo_y = self.matriz_esferica.valida_ponto_matriz(pos_x, pos_y)
        #descobre qual individuo ocupa atualmente a posição para atribuí-lo a posição de quem o está substituindo
        status = self.matriz_status[novo_x, novo_y]
        # if status == Individuo.INFECTADO_TIPO_1:
        #     individuo_ocupante_destino = self.matriz_localizacao[novo_x, novo_y]
        #     print(status)
        #     print(individuo_ocupante_destino)
        #     print(len(self.lista_infectados_tipo_1))

        #     self.lista_infectados_tipo_1[individuo_ocupante_destino].posicao = infectante.posicao
        # elif status == Individuo.INFECTADO_TIPO_2:
        #     individuo_ocupante_destino = self.matriz_localizacao[novo_x, novo_y]
        #     print(status)
        #     print(individuo_ocupante_destino)
        #     print(len(self.lista_infectados_tipo_2))
        #     self.lista_infectados_tipo_2[individuo_ocupante_destino].posicao = infectante.posicao

        # elif status == Individuo.CURADO:
        #     individuo_ocupante_destino = self.matriz_localizacao[novo_x, novo_y]
        #     self.lista_curados[individuo_ocupante_destino].posicao = infectante.posicao
        # elif status == Individuo.MORTO:
        #     individuo_ocupante_destino = self.matriz_localizacao[novo_x, novo_y]
        #     self.lista_matrizes_posicionamento[individuo_ocupante_destino].posicao = infectante.posicao

        self.trocar_status_localizacao(posicao_inicial, (novo_x, novo_y))
class Simulador():
    def __init__(
        self,
        tamanho_matriz,  #numero de linhas e colunas da matriz esférica
        percentual_inicial_tipo1,  #percentual inicial da população que será infectada tipo 1
        percentual_inicial_tipo2,  #percentual inicial da população que será infectada tipo 2
        chance_infeccao,  #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,  #chance de um indivíduo infectado se tornar contagioso
        chance_morte,  #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura
    ):  #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2

        self.num_atualizacoes = 0
        self.lista_infectados_tipo_2 = []
        self.lista_infectados_tipo_1 = []
        self.lista_curados = []
        self.lista_mortos = []
        #lista que guarda o posicionamento
        self.lista_matrizes_posicionamento = []
        #guarda em matriz esparsa o status de saúde de cada elemento
        self.matriz_status = lil_matrix((tamanho_matriz, tamanho_matriz),
                                        dtype=np.uint8)

        #guarda em matriz esparsa a localização do objeto em sua respectiva lista
        self.matriz_localizacao = lil_matrix((tamanho_matriz, tamanho_matriz),
                                             dtype=np.uint32)

        self.fabrica_individuo = Fabrica_individuo(chance_infeccao,
                                                   chance_infeccao_tipo2,
                                                   chance_morte,
                                                   atualizacoes_cura)

        #objeto que é responsável por validar a movimentação no grid n x n
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        self.populacao_inicial = int(tamanho_matriz**2)
        self.num_inicial_tipo2 = int(self.populacao_inicial *
                                     percentual_inicial_tipo2)
        self.num_inicial_tipo1 = int(self.populacao_inicial *
                                     percentual_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (
            self.num_inicial_tipo2 + self.num_inicial_tipo1)
        self.popular(tamanho_matriz)
        dict = {
            'num_sadios': self.num_inicial_sadios,
            'num_infect_t1': self.num_inicial_tipo1,
            'num_infect_t2': self.num_inicial_tipo2,
            'num_curados': 0,
            'num_mortos': 0
        }

        #dataframe que guardará os resultados de cada atualização
        self.dataframe = pd.DataFrame(index=[0])
        self.salvar_posicionamento()

    def salvar_posicionamento(self):
        self.lista_matrizes_posicionamento.append(self.matriz_status)

    def verificar_infeccao(self, lista_infectantes):
        lista_novos_infectados_tipo1 = []
        lista_novos_infectados_tipo2 = []
        #itera sobre sobre a lista de individuos que infectam e cada um realiza a tividade de infectar
        for infectante in lista_infectantes:
            indice_x = infectante.posicao[0]
            indice_y = infectante.posicao[1]
            #busca os vizinhos do infectante atual
            lista_vizinhos = self.matriz_esferica.get_vizinhos(
                indice_x, indice_y)
            #Para cada vizinho, se ele for sadio, é gerado um número aleatório para verificar se foi infectado
            for vizinho in lista_vizinhos:
                x = vizinho[0]
                y = vizinho[1]
                #verificação de SADIO
                if self.matriz_status[x, y] == Individuo.SADIO:
                    #verificação do novo status
                    novo_status = infectante.infectar()
                    #se for um infectado tipo 1
                    if novo_status == Individuo.INFECTADO_TIPO_1:
                        #adiciona na lista de novos tipo 1
                        lista_novos_infectados_tipo1.append(
                            self.fabrica_individuo.criar_individuo(
                                Individuo.INFECTADO_TIPO_1, (x, y)))
                        #modifica o status na matriz de status
                        self.matriz_status[x, y] = Individuo.INFECTADO_TIPO_1
                        self.matriz_localizacao[
                            x, y] = len(lista_novos_infectados_tipo1) - 1
                    if novo_status == Individuo.INFECTADO_TIPO_2:
                        #adiciona na lista de novos tipo 2
                        lista_novos_infectados_tipo2.append(
                            self.fabrica_individuo.criar_individuo(
                                Individuo.INFECTADO_TIPO_2, (x, y)))
                        #modifica o status na matriz de status
                        self.matriz_status[x, y] = Individuo.INFECTADO_TIPO_2
                        self.matriz_localizacao[
                            x, y] = len(lista_novos_infectados_tipo2) - 1
        return lista_novos_infectados_tipo1, lista_novos_infectados_tipo2

    def verificar_morte(self, lista_infectantes_tipo2):
        lista_mortos = []
        for infectante in lista_infectantes_tipo2:
            novo_status = infectante.checagem_morte()
            if novo_status == Individuo.MORTO:
                lista_mortos.append(infectante)
                self.matriz_status[infectante.posicao[0],
                                   infectante.posicao[1]] = Individuo.MORTO

        return lista_mortos

    def verificar_cura(self, lista_infectantes):
        lista_curados = []
        for infectante in lista_infectantes:
            novo_status = infectante.checagem_cura()
            if novo_status == Individuo.CURADO:
                lista_curados.append(indice)
                self.matriz_status[infectante.posicao[0],
                                   infectante.posicao[1]] = Individuo.CURADO

        return lista_curados

    def iterar(self):

        #Verifica os novos infectados a partir dos atuais infectantes na matriz
        lista_novos_infectados_tipo1_1, lista_novos_infectados_tipo2_1 = self.verificar_infeccao(
            self.lista_infectados_tipo_1)
        lista_novos_infectados_tipo1_2, lista_novos_infectados_tipo2_2 = self.verificar_infeccao(
            self.lista_infectados_tipo_2)

        #Verifica morte dos tipo 2
        lista_mortos = self.verificar_morte(self.lista_infectados_tipo_2)

        #retirar os mortos da atualização da lista de infectados tipo 2
        self.lista_infectados_tipo_2 = [
            i for i in self.lista_infectados_tipo_2 if i not in lista_mortos
        ]

        #adiciona os novos mortos na lista geral de mortos
        self.lista_mortos = self.lista_mortos + lista_mortos

        #Verificar cura
        lista_curados_tipo1 = self.verificar_cura(self.lista_infectados_tipo_1)
        lista_curados_tipo2 = self.verificar_cura(self.lista_infectados_tipo_2)

        #retirar os curados das lista de infectados tipo 1 e 2
        self.lista_infectados_tipo_2 = [
            i for i in self.lista_infectados_tipo_2
            if i not in lista_curados_tipo2
        ]
        self.lista_infectados_tipo_1 = [
            i for i in self.lista_infectados_tipo_1
            if i not in lista_curados_tipo1
        ]

        #adiciona os novos curados na lista geral de curados
        self.lista_curados = self.lista_curados + lista_curados_tipo1 + lista_curados_tipo2

        # self.  #movimentar infectantes:
        for infectante in self.lista_infectados_tipo_1:
            self.mover_infectante(infectante)

        for infectante in self.lista_infectados_tipo_2:
            self.mover_infectante(infectante)

        #adicionar os novos infectados tipo 1 e 2 para as respectivas listas
        self.lista_infectados_tipo_2 = self.lista_infectados_tipo_2 + lista_novos_infectados_tipo2_1 + lista_novos_infectados_tipo2_2
        self.lista_infectados_tipo_1 = self.lista_infectados_tipo_1 + lista_novos_infectados_tipo1_1 + lista_novos_infectados_tipo1_2

        #salva os resultados da atualização no dataframe:
        num_mortos = len(self.lista_mortos)

        num_curados = len(self.lista_curados)

        num_tipo_1 = len(self.lista_infectados_tipo_1)

        num_tipo_2 = len(self.lista_infectados_tipo_2)

        dict = {
            'num_sadios':
            self.populacao_inicial - num_mortos - num_curados - num_tipo_1 -
            num_tipo_2,
            'num_infect_t1':
            num_tipo_1,
            'num_infect_t2':
            num_tipo_2,
            'num_curados':
            num_curados,
            'num_mortos':
            num_mortos
        }

        self.dataframe = self.dataframe.append(dict, ignore_index=True)

        #salva a nova matriz de status
        self.salvar_posicionamento()

        #adiciona 1 ao número de atualizações realizadas na matriz
        self.num_atualizacoes += 1

    def popular(self, tamanho_matriz):
        #lista de possíveis combinações de índices da matriz de dados
        permutacoes = permutations(list(range(tamanho_matriz)), 2)
        #conversão para lista de tuplas(x,y)
        lista_indices = list(permutacoes)
        #embaralhamento dos índices
        random.shuffle(lista_indices)

        #cria o primeiro tipo1:
        indice = lista_indices.pop()
        ind_x = indice[0]
        ind_y = indice[1]
        self.lista_infectados_tipo_1.append(
            self.fabrica_individuo.criar_individuo(Individuo.INFECTADO_TIPO_1,
                                                   (ind_x, ind_y)))
        self.matriz_status[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
        self.matriz_localizacao[ind_x, ind_y] = 0

        #cria o restante dos tipos 1
        for i in range(1, self.num_inicial_tipo1):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.lista_infectados_tipo_1.append(
                self.fabrica_individuo.criar_individuo(
                    Individuo.INFECTADO_TIPO_1, (ind_x, ind_y)))
            self.matriz_status[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
            self.matriz_localizacao[ind_x, ind_y] = len(
                self.lista_infectados_tipo_1) - 1

        #cria o restante dos tipo 2:
        for indice in range(self.num_inicial_tipo2):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.lista_infectados_tipo_2.append(
                self.fabrica_individuo.criar_individuo(
                    Individuo.INFECTADO_TIPO_2, (ind_x, ind_y)))
            self.matriz_status[ind_x, ind_y] = Individuo.INFECTADO_TIPO_2
            self.matriz_localizacao[ind_x, ind_y] = len(
                self.lista_infectados_tipo_2) - 1

    def trocar_status_localizacao(self, ponto_ini, ponto_final):
        x_ini = ponto_ini[0]
        y_ini = ponto_ini[1]
        x_fin = ponto_final[0]
        y_fin = ponto_final[1]

        aux1 = self.matriz_status[x_fin, y_fin]
        self.matriz_status[x_fin, y_fin] = self.matriz_status[x_ini, y_ini]
        self.matriz_status[x_ini, y_ini] = aux1

        aux2 = self.matriz_localizacao[x_fin, y_fin]
        self.matriz_localizacao[x_fin, y_fin] = self.matriz_localizacao[x_ini,
                                                                        y_ini]
        self.matriz_localizacao[x_ini, y_ini] = aux2

    def mover_infectante(self, infectante):
        pos_x, pos_y = infectante.posicao[0], infectante.posicao[1]
        rng_posicao = random.random()
        if rng_posicao <= 0.25:
            #move pra cima
            pos_x -= 1
        elif rng_posicao <= 0.5:
            #move pra baixo
            pos_x += 1
        elif rng_posicao <= 0.75:
            #move para esquerda
            pos_y -= 1
        else:
            #move para direita
            pos_y += 1

        novo_x, novo_y = self.matriz_esferica.valida_ponto_matriz(pos_x, pos_y)
        #descobre qual individuo ocupa atualmente a posição para atribuí-lo a posição de quem o está substituindo
        status = self.matriz_status[novo_x, novo_y]
        if status == Individuo.INFECTADO_TIPO_1:
            individuo_ocupante_destino = self.matriz_localizacao[novo_x,
                                                                 novo_y]
            self.lista_infectados_tipo_1[
                individuo_ocupante_destino].posicao = infectante.posicao
        elif status == Individuo.INFECTADO_TIPO_2:
            print(individuo_ocupante_destino)
            individuo_ocupante_destino = self.matriz_localizacao[novo_x,
                                                                 novo_y]
            self.lista_infectados_tipo_2[
                individuo_ocupante_destino].posicao = infectante.posicao

        # elif status == Individuo.CURADO:
        #     individuo_ocupante_destino = self.matriz_localizacao[novo_x, novo_y]
        #     self.lista_curados[individuo_ocupante_destino].posicao = infectante.posicao
        # elif status == Individuo.MORTO:
        #     individuo_ocupante_destino = self.matriz_localizacao[novo_x, novo_y]
        #     self.lista_matrizes_posicionamento[individuo_ocupante_destino].posicao = infectante.posicao

        self.trocar_status_localizacao(infectante.posicao, (novo_x, novo_y))
Ejemplo n.º 6
0
class Simulador():
    SADIO = 0
    INFECTADO_TIPO_1 = 1  #assintomáticos e o infectado inicial
    INFECTADO_TIPO_2 = 2  #sintomático
    CURADO = 3
    MORTO = 4

    def __init__(
        self,
        tamanho_matriz,  #numero de linhas e colunas da matriz esférica
        chance_infeccao,  #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,  #chance de um indivíduo infectado se tornar contagioso
        chance_morte,  #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura,  #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2
        inserir_infectados_aleatorios):
        self.num_atualizacoes = 0
        self.lista_infectados_tipo_2 = []
        self.lista_infectados_tipo_1 = []
        self.num_curados = 0
        self.num_mortos = 0

        self.chance_infeccao = chance_infeccao
        self.chance_infeccao_tipo2 = chance_infeccao_tipo2
        self.chance_morte = chance_morte
        self.atualizacoes_cura = atualizacoes_cura

        self.populacao_inicial = int(tamanho_matriz**2)

        num_inicial_infectados = random.randint(
            0, tamanho_matriz * tamanho_matriz - 1)

        proporcao_t1_t2 = random.random()

        self.num_inicial_tipo1 = round(inserir_infectados_aleatorios *
                                       proporcao_t1_t2 *
                                       num_inicial_infectados)
        print("self.num_inicial_tipo1: ", self.num_inicial_tipo1)
        self.num_inicial_tipo2 = round(inserir_infectados_aleatorios *
                                       (1 - proporcao_t1_t2) *
                                       num_inicial_infectados)
        print("self.num_inicial_tipo2: ", self.num_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (
            self.num_inicial_tipo2 + self.num_inicial_tipo1)

        self.matriz_status = np.zeros(
            (tamanho_matriz, tamanho_matriz), dtype=np.uint8
        )  #lil_matrix((tamanho_matriz, tamanho_matriz),dtype= np.uint8) #
        self.matriz_atualizacoes_cura = np.zeros(
            (tamanho_matriz, tamanho_matriz), dtype=np.uint8
        )  #lil_matrix((tamanho_matriz, tamanho_matriz),dtype= np.uint8)#

        self.dict_resumo = {}

        #self.matriz_status = self.df_individuos.to_numpy()
        self.popular(tamanho_matriz)

        self.lista_matrizes_status = []

        #objeto que é responsável por validar a movimentação no grid n x n
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        dict = {
            'num_sadios': self.num_inicial_sadios,
            'num_infect_t1': self.num_inicial_tipo1,
            'num_infect_t2': self.num_inicial_tipo2,
            'num_curados': 0,
            'num_mortos': 0
        }

        #dataframe que guardará os resultados de cada atualização
        self.dataframe = pd.DataFrame(dict, index=[0])
        self.salvar_posicionamento()

    def criar_individuo(self, status, posicao):

        self.matriz_status[posicao[0], posicao[1]] = status
        if status == self.INFECTADO_TIPO_1 or status == self.INFECTADO_TIPO_2:
            self.matriz_atualizacoes_cura[posicao[0],
                                          posicao[1]] = self.atualizacoes_cura
        else:
            self.matriz_atualizacoes_cura[posicao[0], posicao[1]] = 0

    def salvar_posicionamento(self):

        self.lista_matrizes_status.append(copy.deepcopy(self.matriz_status))

    def verificar_infeccao(self, lista_infectantes):
        lista_novos_infectados_tipo1 = []
        lista_novos_infectados_tipo2 = []
        #itera sobre sobre a lista de individuos que infectam e cada um realiza a tividade de infectar
        for indice_infectante in lista_infectantes:

            #busca os vizinhos do infectante atual
            lista_vizinhos = self.matriz_esferica.get_vizinhos(
                indice_infectante)

            #Para cada vizinho, se ele for sadio, é gerado um número aleatório para verificar se foi infectado
            for indice_vizinho in lista_vizinhos:

                #verificação de SADIO
                if self.verifica_status(indice_vizinho) == self.SADIO:
                    #verificação do novo status
                    novo_status = self.infectar(self.chance_infeccao,
                                                self.chance_infeccao_tipo2)
                    #se for um infectado tipo 1
                    if novo_status == Individuo.INFECTADO_TIPO_1:
                        #adiciona na lista de novos tipo 1
                        lista_novos_infectados_tipo1.append(indice_vizinho)
                    if novo_status == Individuo.INFECTADO_TIPO_2:
                        #adiciona na lista de novos tipo 2
                        lista_novos_infectados_tipo2.append(indice_vizinho)

        return lista_novos_infectados_tipo1, lista_novos_infectados_tipo2

    def checagem_morte_individual(self, chance_morte):
        rng_morte = random.random()
        if rng_morte <= chance_morte:

            return self.MORTO
        else:
            return self.INFECTADO_TIPO_2

    def checar_cura_individual(self, indice):

        self.matriz_atualizacoes_cura[
            indice[0],
            indice[1]] = self.matriz_atualizacoes_cura[indice[0],
                                                       indice[1]] - 1
        if self.matriz_atualizacoes_cura[indice[0], indice[1]] == 0:
            return self.CURADO
        else:
            return self.matriz_status[indice[0], indice[1]]

    def checagem_morte_lista(self, lista_infectantes):
        lista_mortos = []
        for indice_infectante in lista_infectantes:
            novo_status = self.checagem_morte_individual(self.chance_morte)
            if novo_status == Individuo.MORTO:
                lista_mortos.append(indice_infectante)
        return lista_mortos

    def checagem_cura_lista(self, lista_infectantes):
        lista_curados = []
        for indice_infectante in lista_infectantes:
            novo_status = self.checar_cura_individual(indice_infectante)
            if novo_status == Individuo.CURADO:
                lista_curados.append(indice_infectante)

        return lista_curados

    def iterar(self):

        #Verifica os novos infectados por infectantes do tipo 1 e 2
        #print(self.lista_infectados_tipo_1+self.lista_infectados_tipo_2)
        lista_novos_infectados_tipo1, lista_novos_infectados_tipo2 = self.verificar_infeccao(
            self.lista_infectados_tipo_1 + self.lista_infectados_tipo_2)

        for indice in lista_novos_infectados_tipo1:
            self.criar_individuo(self.INFECTADO_TIPO_1, indice)
        for indice in lista_novos_infectados_tipo2:
            self.criar_individuo(self.INFECTADO_TIPO_2, indice)

        #Verifica morte dos infectados tipo 2
        lista_mortos = self.checagem_morte_lista(self.lista_infectados_tipo_2)
        #retira os indices dos individuos mortos da lista de infectados
        self.lista_infectados_tipo_2 = [
            indice for indice in self.lista_infectados_tipo_2
            if indice not in lista_mortos
        ]
        #Instancia individuos mortos na matriz
        for indice in lista_mortos:
            self.criar_individuo(self.MORTO, indice)
        #atualiza o número de mortos na matriz
        self.num_mortos = self.num_mortos + len(lista_mortos)

        #Verifica cura dos infectados tipo 1
        lista_curados_t1 = self.checagem_cura_lista(
            self.lista_infectados_tipo_1)

        #Verifica cura dos infectados tipo 2
        lista_curados_t2 = self.checagem_cura_lista(
            self.lista_infectados_tipo_2)

        #Instancia individuos mortos na matriz
        for indice in lista_curados_t1 + lista_curados_t2:
            self.criar_individuo(self.CURADO, indice)

        #atualiza o número de curados na matriz
        self.num_curados = self.num_curados + len(lista_curados_t1 +
                                                  lista_curados_t2)

        #Atualiza a lista de infectados após a cura dos individuos
        self.lista_infectados_tipo_1 = [
            indice for indice in self.lista_infectados_tipo_1
            if indice not in lista_curados_t1
        ]
        self.lista_infectados_tipo_2 = [
            indice for indice in self.lista_infectados_tipo_2
            if indice not in lista_curados_t2
        ]

        #movimentação
        nova_lista_t1 = []
        for indice in self.lista_infectados_tipo_1:
            nova_lista_t1.append(self.mover_infectante(indice))
        self.lista_infectados_tipo_1 = nova_lista_t1
        #print(self.lista_infectados_tipo_1)
        nova_lista_t2 = []
        for indice in self.lista_infectados_tipo_2:
            nova_lista_t2.append(self.mover_infectante(indice))
        self.lista_infectados_tipo_2 = nova_lista_t2
        #print(self.lista_infectados_tipo_2)

        # matriz_infectantes = matriz_infectantes[matriz_infectantes < 3]
        indices_infectados = list(
            zip(*np.where((self.matriz_status == 1) +
                          (self.matriz_status == 2))))
        # indices_infectados = list(zip(*self.matriz_status.nonzero()))
        #indices_infectados = [indice for indice in indices_infectados if indice not in self.lista_infectados_tipo_1 + self.lista_infectados_tipo_2]
        # self.num_curados = 0
        #self.num_mortos = 0
        self.lista_infectados_tipo_1 = []
        self.lista_infectados_tipo_2 = []
        #novos_t1 = []
        #novos_t2 = []

        for indice in indices_infectados:
            #if indice not in self.lista_infectados_tipo_1 and indice not in self.lista_infectados_tipo_2:
            # print(indice)
            # print(self.matriz_status.shape)
            status = self.matriz_status[indice[0], indice[1]]
            if status == self.INFECTADO_TIPO_1:
                self.lista_infectados_tipo_1.append(indice)
                #novos_t1.append(indice)
            if status == self.INFECTADO_TIPO_2:
                self.lista_infectados_tipo_2.append(indice)
                #novos_t2.append(indice)

        #self.lista_infectados_tipo_1 = self.lista_infectados_tipo_1 + novos_t1
        #self.lista_infectados_tipo_2 = self.lista_infectados_tipo_2 + novos_t2

        dict = {
            'num_sadios':
            self.populacao_inicial - len(self.lista_infectados_tipo_1) -
            len(self.lista_infectados_tipo_2) - self.num_curados -
            self.num_mortos,
            'num_infect_t1':
            len(self.lista_infectados_tipo_1),
            'num_infect_t2':
            len(self.lista_infectados_tipo_2),
            'num_curados':
            self.num_curados,
            'num_mortos':
            self.num_mortos
        }

        self.dataframe = self.dataframe.append(dict, ignore_index=True)

        self.salvar_posicionamento()

        #adiciona 1 ao número de atualizações realizadas na matriz
        self.num_atualizacoes += 1

    def infectar(self, chance_infeccao, chance_infeccao_tipo2):
        saida = Individuo.SADIO

        #número aleatório para chance de infectar o vizinho
        rng_infeccao = random.random()
        if rng_infeccao <= chance_infeccao:
            #número aleatório para chance de infecção tipo 1 ou 2
            rng_infeccao_tipo2 = random.random()
            if rng_infeccao_tipo2 <= chance_infeccao_tipo2:
                saida = Individuo.INFECTADO_TIPO_2
            else:
                saida = Individuo.INFECTADO_TIPO_1
        return saida

    def popular(self, tamanho_matriz):

        #lista de possíveis combinações de índices da matriz de dados
        indice_x = list(range(0, tamanho_matriz))
        indice_y = list(range(0, tamanho_matriz))
        random.shuffle(indice_x)
        random.shuffle(indice_y)

        lista_indices = []
        for x in indice_x:
            for y in indice_y:
                lista_indices.append((x, y))
                if len(lista_indices
                       ) > self.num_inicial_tipo1 + self.num_inicial_tipo1 + 1:
                    break
        #permutacoes = permutations(list(range(tamanho_matriz)),2)
        #conversão para lista de tuplas(x,y)
        #lista_indices = list(zip(indice_x,indice_y))
        #embaralhamento dos índices
        #random.shuffle(lista_indices)

        indice_matriz = 0

        #cria o primeiro tipo1:
        indice = lista_indices[indice_matriz]
        indice_matriz += 1

        self.criar_individuo(Individuo.INFECTADO_TIPO_1, indice)
        self.lista_infectados_tipo_1.append(indice)
        print("criado um tipo 1")
        #cria o restante dos tipos 1
        for i in range(self.num_inicial_tipo1):

            indice = lista_indices[indice_matriz]
            indice_matriz += 1
            self.criar_individuo(Individuo.INFECTADO_TIPO_1, indice)
            self.lista_infectados_tipo_1.append(indice)
        #cria o restante dos tipo 2:

        for indice in range(self.num_inicial_tipo2):

            indice = lista_indices[indice_matriz]
            indice_matriz += 1
            self.criar_individuo(Individuo.INFECTADO_TIPO_2, indice)
            self.lista_infectados_tipo_2.append(indice)

    def trocar(self, matriz, ponto_ini, ponto_final):
        x_ini = ponto_ini[0]
        y_ini = ponto_ini[1]
        x_fin = ponto_final[0]
        y_fin = ponto_final[1]

        aux = matriz[x_fin, y_fin]
        matriz[x_fin, y_fin] = matriz[x_ini, y_ini]
        matriz[x_ini, y_ini] = aux

    def verifica_status(self, indice):
        return self.matriz_status[indice[0], indice[1]]

    def mover_infectante(self, posicao_inicial):
        pos_x, pos_y = posicao_inicial[0], posicao_inicial[1]
        rng_posicao = random.random()
        if rng_posicao <= 0.25:
            #move pra cima
            pos_x -= 1
        elif rng_posicao <= 0.5:
            #move pra baixo
            pos_x += 1
        elif rng_posicao <= 0.75:
            #move para esquerda
            pos_y -= 1
        else:
            #move para direita
            pos_y += 1

        posicao_final = self.matriz_esferica.valida_ponto_matriz(pos_x, pos_y)

        self.trocar(self.matriz_status, posicao_inicial, posicao_final)
        self.trocar(self.matriz_atualizacoes_cura, posicao_inicial,
                    posicao_final)
        return posicao_final

    def executar_simulacao(self):
        while (self.dataframe.iloc[-1]['num_infect_t1'] +
               self.dataframe.iloc[-1]['num_infect_t2']) > 0:
            self.iterar()

        num_sadios_min = self.dataframe.iloc[-1]['num_sadios']
        #descobre linha que ocorreu o máximo de infectados
        indice_infeccao_maxima = self.dataframe[self.dataframe.num_sadios ==
                                                num_sadios_min].index[0]

        metade_infeccao_maxima = int(indice_infeccao_maxima / 2)

        print(metade_infeccao_maxima + 1)
        self.dict_resumo = {
            "pop_inicial":
            self.populacao_inicial,
            "tipo1_inicial":
            self.dataframe.iloc[0]['num_infect_t1'],
            "tipo2_inicial":
            self.dataframe.iloc[0]['num_infect_t2'],
            "n/2_100%_infectados":
            metade_infeccao_maxima,
            "tipo1_n/2":
            self.dataframe.iloc[metade_infeccao_maxima]['num_infect_t1'],
            "tipo2_n/2":
            self.dataframe.iloc[metade_infeccao_maxima]['num_infect_t2'],
            "curados_n/2":
            self.dataframe.iloc[metade_infeccao_maxima]['num_curados'],
            "mortos_n/2":
            self.dataframe.iloc[metade_infeccao_maxima]['num_mortos'],
            "n/2+1_100%_infectados":
            metade_infeccao_maxima,
            "tipo1_n/2+1":
            self.dataframe.iloc[int(metade_infeccao_maxima)]['num_infect_t1'],
            "tipo2_n/2+1":
            self.dataframe.iloc[metade_infeccao_maxima]['num_infect_t2'],
            "curados_n/2+1":
            self.dataframe.iloc[metade_infeccao_maxima]['num_curados'],
            "mortos_n/2+1":
            self.dataframe.iloc[metade_infeccao_maxima]['num_mortos'],
            "n_atualizacoes_100%_infectados":
            indice_infeccao_maxima,
            "tipo1_n":
            self.dataframe.iloc[indice_infeccao_maxima]['num_infect_t1'],
            "tipo2_n":
            self.dataframe.iloc[indice_infeccao_maxima]['num_infect_t2'],
            "curados_n":
            self.dataframe.iloc[indice_infeccao_maxima]['num_curados'],
            "mortos_n":
            self.dataframe.iloc[indice_infeccao_maxima]['num_mortos'],
            "numero_total_atualizacoes":
            self.dataframe.shape[0],
            "sadios_final":
            self.dataframe.iloc[-1]['num_sadios'],
            "curados_final":
            self.dataframe.iloc[-1]['num_curados'],
            "mortos_final":
            self.dataframe.iloc[-1]['num_mortos']
        }
Ejemplo n.º 7
0
class Simulador():

    def __init__(
        self,
        tamanho_matriz,                 #numero de linhas e colunas da matriz esférica
        percentual_inicial_tipo1,       #percentual inicial da população que será infectada tipo 1
        percentual_inicial_tipo2,       #percentual inicial da população que será infectada tipo 2
        chance_infeccao,                #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,          #chance de um indivíduo infectado se tornar contagioso
        chance_morte,                   #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura):             #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2

        self.num_atualizacoes = 0       
        self.individuos_infectados_tipo_2 = []
        self.individuos_infectados_tipo_1 = []
        self.individuos_infectados_curados = []
        self.individuos_infectados_mortos = []
        self.lista_matrizes_posicionamento = []
        self.matriz_status = np.zeros([tamanho_matriz,tamanho_matriz])
        
        self.fabrica_individuo = Fabrica_individuo(
                                                chance_infeccao,
                                                chance_infeccao_tipo2, 
                                                chance_morte, 
                                                atualizacoes_cura)

        self.matriz_individuos = pd.DataFrame(columns=range(tamanho_matriz), index=range(tamanho_matriz))
        self.matriz_individuos.loc[:] = self.fabrica_individuo.criar_individuo(Individuo.SADIO,(0,0))
        self.matriz_status[:] = Individuo.SADIO
        #objeto que é responsável por validar a movimentação no grid n x n    
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)
        
        self.populacao_inicial = int(tamanho_matriz**2)
        self.num_inicial_tipo2 = int(self.populacao_inicial * percentual_inicial_tipo2)
        self.num_inicial_tipo1 = int(self.populacao_inicial * percentual_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (self.num_inicial_tipo2 + self.num_inicial_tipo1)
        self.popular(tamanho_matriz)
        dict = {
                'num_sadios':self.num_inicial_sadios,
                'num_infect_t1':self.num_inicial_tipo1,
                'num_infect_t2':self.num_inicial_tipo2,
                'num_curados':0,
                'num_mortos':0}
            

        #dataframe que guardará os resultados de cada atualização  
        self.dataframe = pd.DataFrame(dict, index = [0])
        self.salvar_posicionamento()
    
    
  
    def salvar_posicionamento(self):
        self.lista_matrizes_posicionamento.append(self.matriz_status)
        



    def iterar(self):

        #itera sobre sobre a lista de individuos que infectam e cada um realiza a tividade de infectar
        pass




        
    
    def popular(self, tamanho_matriz):
        #lista de possíveis combinações de índices da matriz de dados
        permutacoes = permutations(list(range(tamanho_matriz)),2)
        #conversão para lista de tuplas(x,y)
        lista_indices = list(permutacoes)
        #embaralhamento dos índices
        random.shuffle(lista_indices)
        
        #cria o primeiro tipo1:
        indice = lista_indices.pop()
        ind_x = indice[0]
        ind_y = indice[1]
        self.matriz_individuos.loc[ind_x,ind_y] = self.fabrica_individuo.criar_individuo(Individuo.INFECTADO_TIPO_1,(ind_x,ind_y))
        #self.matriz_individuos[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
        self.individuos_infectados_tipo_1.append((ind_x,ind_y))
        self.matriz_status[ind_x,ind_y] = Individuo.INFECTADO_TIPO_1
        #cria o restante dos tipos 1
        for i in range(1,self.num_inicial_tipo1):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.matriz_individuos.loc[ind_x,ind_y] = self.fabrica_individuo.criar_individuo(Individuo.INFECTADO_TIPO_1,(ind_x,ind_y))
            #self.matriz_individuos[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
            self.individuos_infectados_tipo_1.append((ind_x,ind_y))
            self.matriz_status[ind_x,ind_y] = Individuo.INFECTADO_TIPO_1

        #cria o restante dos tipo 2:
        for indice in range(self.num_inicial_tipo2):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.matriz_individuos.loc[ind_x,ind_y] = self.fabrica_individuo.criar_individuo(Individuo.INFECTADO_TIPO_2,(ind_x,ind_y))
            #self.matriz_individuos[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
            self.individuos_infectados_tipo_2.append((ind_x,ind_y))
            self.matriz_status[ind_x,ind_y] = Individuo.INFECTADO_TIPO_2
    
      


    def mover_infectado(self, individuo: Individuo):
        pos_x, pos_y = individuo.posicao[0], individuo.posicao[1]
        rng_posicao = random.random()
        if rng_posicao <=0.25:
            #move pra cima
            pos_x -= 1
        elif rng_posicao <=0.5:
            #move pra baixo
            pos_x += 1
        elif rng_posicao <=0.75:
            #move para esquerda
            pos_y -= 1
        else:
            #move para direita
            pos_y += 1
        
        novo_x, novo_y = self.matriz_esferica.validar(pos_x, pos_y)
        #troca os valores no dataframe
        aux = self.matriz_individuos.loc[novo_x, novo_y]
        self.matriz_individuos.loc[novo_x, novo_y] = self.matriz_individuos.loc[pos_x, pos_y]
        self.matriz_individuos.loc[pos_x, pos_y] = aux

        #troca os valores na matriz de status
        aux = self.matriz_status[novo_x, novo_y]
        self.self.matriz_status[novo_x, novo_y] = self.matriz_status[pos_x, pos_y]
        self.self.matriz_status[pos_x, pos_y] = aux


        return (novo_x, novo_y)
    def __init__(
        self,
        tamanho_matriz,  #numero de linhas e colunas da matriz esférica
        percentual_inicial_tipo1,  #percentual inicial da população que será infectada tipo 1
        percentual_inicial_tipo2,  #percentual inicial da população que será infectada tipo 2
        chance_infeccao,  #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,  #chance de um indivíduo infectado se tornar contagioso
        chance_morte,  #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura
    ):  #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2

        self.num_atualizacoes = 0
        self.lista_infectados_tipo_2 = []
        self.lista_infectados_tipo_1 = []
        self.num_curados = 0
        self.num_mortos = 0

        self.chance_infeccao = chance_infeccao
        self.chance_infeccao_tipo2 = chance_infeccao_tipo2
        self.chance_morte = chance_morte
        self.atualizacoes_cura = atualizacoes_cura

        self.populacao_inicial = int(tamanho_matriz**2)
        self.num_inicial_tipo2 = int(self.populacao_inicial *
                                     percentual_inicial_tipo2)
        self.num_inicial_tipo1 = 1 + int(
            self.populacao_inicial * percentual_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (
            self.num_inicial_tipo2 + self.num_inicial_tipo1)

        self.matriz_status = lil_matrix((tamanho_matriz, tamanho_matriz),
                                        dtype=np.uint8)
        self.matriz_atualizacoes_cura = lil_matrix(
            (tamanho_matriz, tamanho_matriz), dtype=np.uint8)

        #self.matriz_status = self.df_individuos.to_numpy()
        self.popular(tamanho_matriz)

        self.lista_matrizes_status = []

        #objeto que é responsável por validar a movimentação no grid n x n
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        # dict = {
        #         'num_sadios':self.num_inicial_sadios,
        #         'num_infect_t1':self.num_inicial_tipo1,
        #         'num_infect_t2':self.num_inicial_tipo2,
        #         'num_curados':0,
        #         'num_mortos':0}

        dict = {
            'num_sadios':
            self.dataframe[-1:]['num_sadios'] -
            np.sum(self.matriz_status[self.matriz_status != 0].toarray()),
            'num_infect_t1':
            np.sum(self.matriz_status[self.matriz_status == 1].toarray()),
            'num_infect_t2':
            np.sum(self.matriz_status[self.matriz_status == 2].toarray()),
            'num_curados':
            np.sum(self.matriz_status[self.matriz_status == 3].toarray()),
            'num_mortos':
            np.sum(self.matriz_status[self.matriz_status == 4].toarray())
        }

        #dataframe que guardará os resultados de cada atualização
        self.dataframe = pd.DataFrame(dict, index=[0])
        self.salvar_posicionamento()
class Simulador():

    def __init__(
        self,
        tamanho_matriz,                 #numero de linhas e colunas da matriz esférica
        percentual_inicial_tipo1,       #percentual inicial da população que será infectada tipo 1
        percentual_inicial_tipo2,       #percentual inicial da população que será infectada tipo 2
        chance_infeccao,                #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,          #chance de um indivíduo infectado se tornar contagioso
        chance_morte,                   #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura):             #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2

        self.num_atualizacoes = 0       
        self.individuos_infectados_tipo_2 = []
        self.individuos_infectados_tipo_1 = []
        self.individuos_curados = []
        self.individuos_mortos = []
        self.lista_matrizes_posicionamento = []
        self.matriz_status = np.zeros([tamanho_matriz,tamanho_matriz], dtype= int)
        
        self.fabrica_individuo = Fabrica_individuo(
                                                chance_infeccao,
                                                chance_infeccao_tipo2, 
                                                chance_morte, 
                                                atualizacoes_cura)

        self.matriz_individuos = pd.DataFrame(columns=range(tamanho_matriz), index=range(tamanho_matriz))
        self.matriz_individuos.loc[:] = self.fabrica_individuo.criar_individuo(Individuo.SADIO,(0,0))
        self.matriz_status[:] = Individuo.SADIO
        #objeto que é responsável por validar a movimentação no grid n x n    
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)
        
        self.populacao_inicial = int(tamanho_matriz**2)
        self.num_inicial_tipo2 = int(self.populacao_inicial * percentual_inicial_tipo2)
        self.num_inicial_tipo1 = int(self.populacao_inicial * percentual_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (self.num_inicial_tipo2 + self.num_inicial_tipo1)
        self.popular(tamanho_matriz)
        dict = {
                'num_sadios':self.num_inicial_sadios,
                'num_infect_t1':self.num_inicial_tipo1,
                'num_infect_t2':self.num_inicial_tipo2,
                'num_curados':0,
                'num_mortos':0}
            

        #dataframe que guardará os resultados de cada atualização  
        self.dataframe = pd.DataFrame(index = [0])
        self.salvar_posicionamento()
    
    
  
    def salvar_posicionamento(self):
        self.lista_matrizes_posicionamento.append(self.matriz_status)
        

    def verificar_infeccao(self, lista_infectantes):
        lista_novos_infectados_tipo1 = []
        lista_novos_infectados_tipo2 = []
        #itera sobre sobre a lista de individuos que infectam e cada um realiza a tividade de infectar
        for indice in lista_infectantes:
            #busca os vizinhos do infectante atual
            lista_vizinhos = self.matriz_esferica.get_vizinhos(indice[0], indice[1])
            #Para cada vizinho, se ele for sadio, é gerado um número aleatório para verificar se foi infectado
            for vizinho in lista_vizinhos:
                x = vizinho[0]
                y = vizinho[1]
                #verificação de SADIO
                if self.matriz_status[x,y] == Individuo.SADIO:
                    #verificação do novo status
                    novo_status = self.matriz_individuos.loc[indice[0], indice[1]].infectar()
                    #se for um infectado tipo 1
                    if novo_status == Individuo.INFECTADO_TIPO_1:
                        #adiciona na lista de novos tipo 1
                        lista_novos_infectados_tipo1.append((x,y))
                        #modifica o status do objeto recém infectado
                        self.matriz_individuos.loc[x,y].status = Individuo.INFECTADO_TIPO_1
                        #modifica o status na matriz de status
                        self.matriz_status[x,y] = Individuo.INFECTADO_TIPO_1
                    if novo_status == Individuo.INFECTADO_TIPO_2:
                        #adiciona na lista de novos tipo 2
                        lista_novos_infectados_tipo2.append((x,y))
                        #modifica o status do objeto recém infectado
                        self.matriz_individuos.loc[x,y].status = Individuo.INFECTADO_TIPO_2
                        #modifica o status na matriz de status
                        self.matriz_status[x,y] = Individuo.INFECTADO_TIPO_2
        return lista_novos_infectados_tipo1, lista_novos_infectados_tipo2

    def verificar_morte(self, lista_infectantes_tipo2):
        lista_mortos = []
        for indice in lista_infectantes_tipo2:
            novo_status = self.matriz_individuos.loc[indice[0], indice[1]].checagem_morte()
            if novo_status == Individuo.MORTO:
                lista_mortos.append(indice)
                self.matriz_status[indice[0], indice[1]] = Individuo.MORTO

        return lista_mortos
    
    
    def verificar_cura(self, lista_infectantes):
        lista_curados = []
        for indice in lista_infectantes:
            novo_status = self.matriz_individuos.loc[indice[0], indice[1]].checagem_cura()
            if novo_status == Individuo.CURADO:
                lista_curados.append(indice)
                self.matriz_status[indice[0], indice[1]] = Individuo.CURADO
        
        return lista_curados
    
    
    
    
    def iterar(self):

        #Verifica os novos infectados a partir dos atuais infectantes na matriz
        lista_novos_infectados_tipo1_1, lista_novos_infectados_tipo2_1 = self.verificar_infeccao(self.individuos_infectados_tipo_1)
        lista_novos_infectados_tipo1_2, lista_novos_infectados_tipo2_2 = self.verificar_infeccao(self.individuos_infectados_tipo_2)
        
        #Verifica morte dos tipo 2
        lista_mortos = self.verificar_morte(self.individuos_infectados_tipo_2)
        
        self.individuos_infectados_mortos

        #retirar os mortos da lista de infectados tipo 2
        ###
        """
        """
        #adiciona os novos mortos na lista geral de mortos
        # self.individuos_infectados_mortos



        #Verificar cura
        lista_curados_tipo1 = verificar_cura(self.individuos_infectados_tipo_1)
        lista_curados_tipo2 = verificar_cura(self.individuos_infectados_tipo_2)

        #retirar os curados das lista de infectados tipo 1 e 2
        """
        """

        #adiciona os novos curados na lista geral de curados
        # self.  #movimentar infectantes:
        for i in range(len(self.individuos_infectados_tipo_1)):
            self.individuos_infectados_tipo_1[i] = self.mover_infectante(self.individuos_infectados_tipo_1[i])
        
        for i in range(len(self.individuos_infectados_tipo_2)):
            self.individuos_infectados_tipo_2[i] = self.mover_infectante(self.individuos_infectados_tipo_2[i])


        #adicionar os novos infectados tipo 1 e 2 para as respectivas listas
        # self.individuos_infectados_tipo_2 = []
        # self.individuos_infectados_tipo_1 = []    

        

        #salva os resultados da atualização no dataframe:
        num_mortos = len(self.individuos_mortos)
        
        num_curados = len(self.individuos_curados)

        num_tipo_1 = len(self.individuos_infectados_tipo_1)

        num_tipo_2 = len(self.individuos_infectados_tipo_2)

        
        #salva a nova matriz de status
        self.salvar_posicionamento()

        #adiciona 1 ao número de atualizações realizadas na matriz
        self.num_atualizacoes +=1

        
    
    def popular(self, tamanho_matriz):
        #lista de possíveis combinações de índices da matriz de dados
        permutacoes = permutations(list(range(tamanho_matriz)),2)
        #conversão para lista de tuplas(x,y)
        lista_indices = list(permutacoes)
        #embaralhamento dos índices
        random.shuffle(lista_indices)
        
        #cria o primeiro tipo1:
        indice = lista_indices.pop()
        ind_x = indice[0]
        ind_y = indice[1]
        self.matriz_individuos.loc[ind_x,ind_y] = self.fabrica_individuo.criar_individuo(Individuo.INFECTADO_TIPO_1,(ind_x,ind_y))
        #self.matriz_individuos[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
        self.individuos_infectados_tipo_1.append((ind_x,ind_y))
        self.matriz_status[ind_x,ind_y] = Individuo.INFECTADO_TIPO_1
        #cria o restante dos tipos 1
        for i in range(1,self.num_inicial_tipo1):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.matriz_individuos.loc[ind_x,ind_y] = self.fabrica_individuo.criar_individuo(Individuo.INFECTADO_TIPO_1,(ind_x,ind_y))
            #self.matriz_individuos[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
            self.individuos_infectados_tipo_1.append((ind_x,ind_y))
            self.matriz_status[ind_x,ind_y] = Individuo.INFECTADO_TIPO_1

        #cria o restante dos tipo 2:
        for indice in range(self.num_inicial_tipo2):
            indice = lista_indices.pop()
            ind_x = indice[0]
            ind_y = indice[1]
            self.matriz_individuos.loc[ind_x,ind_y] = self.fabrica_individuo.criar_individuo(Individuo.INFECTADO_TIPO_2,(ind_x,ind_y))
            #self.matriz_individuos[ind_x, ind_y] = Individuo.INFECTADO_TIPO_1
            self.individuos_infectados_tipo_2.append((ind_x,ind_y))
            self.matriz_status[ind_x,ind_y] = Individuo.INFECTADO_TIPO_2
    
      


    def mover_infectante(self, indice):
        pos_x, pos_y = indice[0], indice[1]
        rng_posicao = random.random()
        if rng_posicao <=0.25:
            #move pra cima
            pos_x -= 1
        elif rng_posicao <=0.5:
            #move pra baixo
            pos_x += 1
        elif rng_posicao <=0.75:
            #move para esquerda
            pos_y -= 1
        else:
            #move para direita
            pos_y += 1
        
        novo_x, novo_y = self.matriz_esferica.validar(pos_x, pos_y)
        #troca os valores no dataframe
        aux = self.matriz_individuos.loc[novo_x, novo_y]
        self.matriz_individuos.loc[novo_x, novo_y] = self.matriz_individuos.loc[pos_x, pos_y]
        self.matriz_individuos.loc[pos_x, pos_y] = aux

        #troca os valores na matriz de status
        aux = self.matriz_status[novo_x, novo_y]
        self.self.matriz_status[novo_x, novo_y] = self.matriz_status[pos_x, pos_y]
        self.self.matriz_status[pos_x, pos_y] = aux


        return (novo_x, novo_y)
Ejemplo n.º 10
0
    def __init__(
        self,
        tamanho_matriz,  #numero de linhas e colunas da matriz esférica
        percentual_inicial_tipo1,  #percentual inicial da população que será infectada tipo 1
        percentual_inicial_tipo2,  #percentual inicial da população que será infectada tipo 2
        chance_infeccao,  #chance que um infectado tipo 2 tem de infectar um indivíduo saudável
        chance_infeccao_tipo2,  #chance de um indivíduo infectado se tornar contagioso
        chance_morte,  #chance de um indivíduo tipo 2 morrer ao fim de uma atualização
        atualizacoes_cura
    ):  #número de atualizações necessárias para a cura de um indivíduo tipo 1 ou 2

        self.num_atualizacoes = 0
        self.lista_infectados_tipo_2 = []
        self.lista_infectados_tipo_1 = []
        self.num_curados = 0
        self.num_mortos = 0

        self.chance_infeccao = chance_infeccao
        self.chance_infeccao_tipo2 = chance_infeccao_tipo2
        self.chance_morte = chance_morte
        self.fabrica_individuo = Fabrica_individuo(atualizacoes_cura)
        self.df_individuos = pd.DataFrame(index=range(tamanho_matriz),
                                          columns=range(tamanho_matriz))
        self.df_individuos.fillna(
            self.fabrica_individuo.criar_individuo(10, (0, 0)))
        print(self.df_individuos)

        #self.df_individuos.iloc[0,0] = 0
        #lista que guarda o posicionamento
        self.lista_matrizes_posicionamento = []
        #guarda em matriz esparsa o status de saúde de cada elemento
        self.matriz_status = lil_matrix((tamanho_matriz, tamanho_matriz),
                                        dtype=np.uint8)

        #guarda em matriz esparsa a localização do objeto em sua respectiva lista
        self.matriz_localizacao = lil_matrix((tamanho_matriz, tamanho_matriz),
                                             dtype=np.uint32)

        self.fabrica_individuo = Fabrica_individuo(atualizacoes_cura)

        #objeto que é responsável por validar a movimentação no grid n x n
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        self.populacao_inicial = int(tamanho_matriz**2)
        self.num_inicial_tipo2 = int(self.populacao_inicial *
                                     percentual_inicial_tipo2)
        self.num_inicial_tipo1 = int(self.populacao_inicial *
                                     percentual_inicial_tipo1)
        self.num_inicial_sadios = self.populacao_inicial - (
            self.num_inicial_tipo2 + self.num_inicial_tipo1)
        self.popular(tamanho_matriz)
        dict = {
            'num_sadios': self.num_inicial_sadios,
            'num_infect_t1': self.num_inicial_tipo1,
            'num_infect_t2': self.num_inicial_tipo2,
            'num_curados': 0,
            'num_mortos': 0
        }

        #dataframe que guardará os resultados de cada atualização
        self.dataframe = pd.DataFrame(index=[0])
        self.salvar_posicionamento()
    def __init__(self, tamanho_matriz):
        self.num_iteracoes = 0
        self.matriz_individuos = []
        self.matriz_esferica = Matriz_esferica(tamanho_matriz)

        self.dataframe = pd.DataFrame(columns= [''])