From 6d4ce034a6ecb4e09c32628d187eec450fbae01f Mon Sep 17 00:00:00 2001
From: Pedro Folloni Pesserl <fpesserl7@gmail.com>
Date: Thu, 2 Feb 2023 02:14:45 -0300
Subject: [PATCH] finish simulation

---
 t1/libconjunto.c |   7 +-
 t1/makefile      |   2 +-
 t1/mundo.c       | 272 +++++++++++++++++++++++++++++++----------------
 3 files changed, 187 insertions(+), 94 deletions(-)

diff --git a/t1/libconjunto.c b/t1/libconjunto.c
index 7e16126..daf98e3 100644
--- a/t1/libconjunto.c
+++ b/t1/libconjunto.c
@@ -207,9 +207,10 @@ void imprime_cjt(conjunto_t *c) {
 	}
 
 	int i;
-	for (i = 0; i < cardinalidade_cjt(c)-1; i++)
-		printf("%d ", c->v[i]);
-	printf("%d\n", c->v[cardinalidade_cjt(c)-1]);
+	printf("%d", c->v[0]);
+	for (i = 1; i < cardinalidade_cjt(c); i++)
+		printf(" %d", c->v[i]);
+	printf("\n");
 }
 
 void inicia_iterador_cjt(conjunto_t *c) {
diff --git a/t1/makefile b/t1/makefile
index f0015ca..5cbc273 100644
--- a/t1/makefile
+++ b/t1/makefile
@@ -1,6 +1,6 @@
 # Makefile de exemplo (Manual do GNU Make)
      
-CFLAGS = -Wall -std=c90 -g  # flags de compilacao
+CFLAGS = -Wall -std=c90 -g# flags de compilacao
 LDFLAGS = -lm
 
 CC = gcc
diff --git a/t1/mundo.c b/t1/mundo.c
index 9694d5d..f089556 100644
--- a/t1/mundo.c
+++ b/t1/mundo.c
@@ -6,10 +6,10 @@
 #include "libfila.h"
 #include "liblef.h"
 
-#define MEM_ERROR_EXIT										\
-	do {													\
-		printf("Erro: não foi possível alocar memória.");	\
-		exit(1);											\
+#define MEM_ERROR_EXIT												\
+	do {															\
+		fprintf(stderr, "Erro: não foi possível alocar memória.");	\
+		exit(1);													\
 	} while(0)
 
 #define CHEGADA 0
@@ -44,6 +44,7 @@ typedef struct {
 	int n_locais;
 	heroi_t *herois;
 	local_t *locais;
+	conjunto_t **missoes;
 } mundo_t;
 
 /* retorna um inteiro aleatório entre a e b (inclusive) */
@@ -151,8 +152,14 @@ mundo_t *cria_mundo(lef_t *lista_de_eventos) {
 		adiciona_ordem_lef(lista_de_eventos, &evento_chegada_heroi);
 	}
 
-	/* para cada missao, cria evento e insere na lef */
+	/* cria vetor de missões */
+	if ( !(m->missoes = malloc(m->n_missoes * sizeof(conjunto_t*))) ) {
+		MEM_ERROR_EXIT;
+	}
+	/* preenche vetor de missões, inicialmente com NULL;
+	 * para cada missao, cria evento e insere na lef */
 	for (i = 0; i < m->n_missoes; i++) {
+		m->missoes[i] = NULL;
 		evento_t evento_missao = { aleat(0, m->fim_do_mundo), MISSAO, i, 0 };
 		adiciona_ordem_lef(lista_de_eventos, &evento_missao);
 	}
@@ -176,103 +183,188 @@ int velocidade_heroi(heroi_t heroi) {
 	return 100 - max(0, heroi.idade - 40);
 }
 
+conjunto_t *escolhe_menor_equipe(conjunto_t *missao, int id_missao, mundo_t *m, local_t *local_encontrado) {
+	conjunto_t *menor;
+	if ( !(menor = cria_cjt(cardinalidade_cjt(m->cj_habilidades))) )
+		MEM_ERROR_EXIT;
+	conjunto_t *uniao_old;
+	conjunto_t *uniao;
+	int i, j, id_heroi_atual;
+	
+	for (i = 0; i < m->n_locais; i++) {
+		if (vazio_cjt(m->locais[i].publico)) continue;
+
+		/* copia o conjunto de habilidades do primeiro herói do local atual */
+		inicia_iterador_cjt(m->locais[i].publico);
+		incrementa_iterador_cjt(m->locais[i].publico, &id_heroi_atual);
+		if ( !(uniao = copia_cjt(m->herois[id_heroi_atual].habilidades_do_heroi)) )
+			MEM_ERROR_EXIT;
+
+		/* faz a união entre os conjuntos de habilidades de todos os heróis do local atual */
+		for (j = 1; j < cardinalidade_cjt(m->locais[i].publico); j++) {
+			uniao_old = uniao;
+			incrementa_iterador_cjt(m->locais[i].publico, &id_heroi_atual);
+			uniao = uniao_cjt(uniao, m->herois[id_heroi_atual].habilidades_do_heroi);
+			uniao_old = destroi_cjt(uniao_old);
+		}
+
+		printf("%6d:MISSAO %4d HAB_EQL %d:", m->tempo_atual, id_missao, m->locais[i].id);
+		imprime_cjt(uniao);
+
+		/* compara se o conjunto construído contém a missao e é menor que o achado anteriormente */
+		if (contido_cjt(missao, uniao)) {
+			if (vazio_cjt(menor) || cardinalidade_cjt(uniao) < cardinalidade_cjt(menor)) {
+				menor = destroi_cjt(menor);
+				if ( !(menor = copia_cjt(uniao)) )
+					MEM_ERROR_EXIT;
+				*local_encontrado = m->locais[i];
+			}
+		}
+		uniao = destroi_cjt(uniao);
+	}
+	
+	return menor;
+}
+
+void trata_evento_chegada(int id_heroi, int id_local, mundo_t *m, lef_t *lista_de_eventos) {
+	printf("%6d:CHEGA HEROI %2d Local %d (%2d/%2d), ",
+			m->tempo_atual,
+			id_heroi,
+			id_local,
+			cardinalidade_cjt(m->locais[id_local].publico),
+			m->locais[id_local].lotacao_max);
+
+	if (local_lotado(id_local, m)) {
+		if (heroi_tem_paciencia(id_heroi, id_local, m)) {
+			insere_fila(m->locais[id_local].fila, id_heroi);
+			printf("FILA %d\n", tamanho_fila(m->locais[id_local].fila));
+			return;
+		}
+		printf("DESISTE\n");
+		evento_t saida = { m->tempo_atual, SAIDA, id_heroi, id_local };
+		adiciona_ordem_lef(lista_de_eventos, &saida);
+		return;
+	}
+
+	printf("ENTRA\n");
+	insere_cjt(m->locais[id_local].publico, id_heroi);
+	int t_permanencia_local = max(1, m->herois[id_heroi].paciencia/10 + aleat(-2,6));
+	evento_t saida = { m->tempo_atual + t_permanencia_local, SAIDA, id_heroi, id_local };
+	adiciona_ordem_lef(lista_de_eventos, &saida);
+	return;
+}
+
 int main() {
-	srand(time(0));
+	/* srand(time(0)); */
+	srand(0);
 
 	lef_t *lista_de_eventos;
 	if ( !(lista_de_eventos = cria_lef()) )
 		MEM_ERROR_EXIT;
 
-	mundo_t *mundo;
-	mundo = cria_mundo(lista_de_eventos);
-	printf("inicializou o mundo!\n");
-	printf("tamanho do mundo: %d\n", mundo->tamanho_mundo);
-	printf("conjunto de habilidades do mundo:\n");
-	imprime_cjt(mundo->cj_habilidades);
+	mundo_t *mundo = cria_mundo(lista_de_eventos);
 	
-	/* int i = 0; */
-	/* nodo_lef_t *exemplo = lista_de_eventos->Primeiro; */
-	/* printf("eventos alocados na lef:\n"); */
-	/* while (exemplo) { */
-	/* 	printf("tempo do evento %d: %d\n", i, exemplo->evento->tempo); */
-	/* 	printf(" tipo do evento %d: ", i); */
-	/* 	switch (exemplo->evento->tipo) { */
-	/* 		case CHEGADA: */
-	/* 			printf("CHEGADA\n"); */
-	/* 			break; */
-	/* 		case SAIDA: */
-	/* 			printf("SAIDA\n"); */
-	/* 			break; */
-	/* 		case MISSAO: */
-	/* 			printf("MISSAO\n"); */
-	/* 			break; */
-	/* 		case FIM: */
-	/* 			printf("FIM\n"); */
-	/* 			break; */
-	/* 		default: */
-	/* 			printf("deu alguma coisa muito louca aqui\n"); */
-	/* 			break; */
-	/* 	} */
-	/* 	i++; */
-	/* 	exemplo = exemplo->prox; */
-	/* } */
-
-	/* ciclo da simulação */
 	evento_t *evento_atual;
-	evento_atual = obtem_primeiro_lef(lista_de_eventos);
-	mundo->tempo_atual = evento_atual->tempo;
-	/* trata o evento e atualiza estado do sistema */
-
-	/* TODO: criar função wrapper para tratar os eventos e poder criar variaveis temporarias */
-
-	switch (evento_atual->tipo) {
-		case CHEGADA:
-			evento_t saida;
-			int id_heroi = evento_atual->dado1;
-			int id_local = evento_atual->dado2;
-			if (local_lotado(id_local, mundo)) {
-				if (heroi_tem_paciencia(id_heroi, id_local, mundo)) {
-					insere_fila(mundo->locais[id_local].fila, id_heroi);
+	/* ciclo da simulação */
+	while ( lista_de_eventos && (evento_atual = obtem_primeiro_lef(lista_de_eventos)) ) {
+		mundo->tempo_atual = evento_atual->tempo;
+
+		/* trata o evento e atualiza estado do sistema */
+		int id_heroi, id_local, id_missao, i;
+		switch (evento_atual->tipo) {
+			case CHEGADA:
+				trata_evento_chegada(evento_atual->dado1, evento_atual->dado2, mundo, lista_de_eventos);
+				break;
+
+			case SAIDA: ;
+				id_heroi = evento_atual->dado1;
+				id_local = evento_atual->dado2;
+				printf("%6d:SAIDA HEROI %2d Local %d (%2d/%2d)",
+					mundo->tempo_atual,
+					id_heroi,
+					id_local,
+					cardinalidade_cjt(mundo->locais[id_local].publico),
+					mundo->locais[id_local].lotacao_max);
+
+				if (pertence_cjt(mundo->locais[id_local].publico, id_heroi)) {
+					retira_cjt(mundo->locais[id_local].publico, id_heroi);
+					if (!vazia_fila(mundo->locais[id_local].fila)) {
+						int id_heroi_fila;
+						retira_fila(mundo->locais[id_local].fila, &id_heroi_fila);
+						printf(", REMOVE FILA HEROI %d", id_heroi_fila);
+						evento_t chegada_heroi_fila = { mundo->tempo_atual, CHEGADA, id_heroi_fila, id_local };
+						adiciona_inicio_lef(lista_de_eventos, &chegada_heroi_fila);
+					}
+				}
+				printf("\n");
+
+				int id_local_destino = aleat(0, mundo->n_locais-1);
+				int t_deslocamento = distancia(mundo->locais[id_local], mundo->locais[id_local_destino]) / velocidade_heroi(mundo->herois[id_heroi]);
+				evento_t chegada_heroi = { mundo->tempo_atual + t_deslocamento/15, CHEGADA, id_heroi, id_local_destino };
+				adiciona_ordem_lef(lista_de_eventos, &chegada_heroi);
+				break;
+
+			case MISSAO: ;
+				id_missao = evento_atual->dado1;
+				local_t local_encontrado;
+				conjunto_t *missao;
+				if (mundo->missoes[id_missao] == NULL)
+					if ( !(mundo->missoes[id_missao] = cria_subcjt_cjt(mundo->cj_habilidades, aleat(3, 6))) )
+						MEM_ERROR_EXIT;
+				
+				missao = mundo->missoes[id_missao];
+				printf("%6d:MISSAO %4d HAB_REQ ", mundo->tempo_atual, id_missao);
+				imprime_cjt(missao);
+				
+				conjunto_t *equipe_escolhida = escolhe_menor_equipe(missao, id_missao, mundo, &local_encontrado);
+
+				printf("%6d:MISSAO %4d ", mundo->tempo_atual, id_missao);
+				if (vazio_cjt(equipe_escolhida)) {
+					printf("IMPOSSIVEL\n");
+					evento_t nova_tentativa = { aleat(mundo->tempo_atual, mundo->fim_do_mundo), MISSAO, id_missao, 0 };
+					adiciona_ordem_lef(lista_de_eventos, &nova_tentativa);
 				} else {
-					saida = { mundo->tempo_atual, SAIDA, id_heroi, id_local };
-					adiciona_ordem_lef(lista_de_eventos, &saida);
+					printf("HER_EQS %d:", local_encontrado.id);
+					imprime_cjt(local_encontrado.publico);
+
+					int id_heroi_encontrado;
+					inicia_iterador_cjt(local_encontrado.publico);
+					for (i = 0; i < cardinalidade_cjt(local_encontrado.publico); i++) {
+						incrementa_iterador_cjt(local_encontrado.publico, &id_heroi_encontrado);
+						(mundo->herois[id_heroi_encontrado].exp)++;
+					}
+					missao = destroi_cjt(missao);
+					mundo->missoes[id_missao] = NULL;
 				}
-			} else {
-				insere_cjt(mundo->locais[id_local].publico, id_heroi);
-				int t_permanencia_local = max(1, mundo->herois[id_heroi].paciencia/10 + aleat(-2,6));
-				saida = { mundo->tempo_atual + t_permanencia_local, SAIDA, id_heroi, id_local };
-				adiciona_ordem_lef(lista_de_eventos, &saida);
-			}
-			break;
-
-		case SAIDA:
-			evento_t chegada_heroi, chegada_heroi_fila;
-			int id_heroi = evento_atual->dado1;
-			int id_local = evento_atual->dado2;
-			if (pertence_cjt(mundo->locais[id_local].publico, id_heroi)) {
-				retira_cjt (mundo->locais[id_local].publico, id_heroi);
-				if (!vazia_fila(mundo->locais[id_local].fila)) {
-					int id_heroi_fila;
-					retira_fila(mundo->locais[id_local].fila, &id_heroi_fila);
-					chegada_heroi_fila = { mundo->tempo_atual, CHEGADA, id_heroi_fila, id_local };
-					adiciona_inicio_lef(lista_de_eventos, &chegada_heroi_fila);
+				equipe_escolhida = destroi_cjt(equipe_escolhida);
+				break;
+
+			case FIM:
+				printf("%6d:FIM\n", mundo->tempo_atual);
+				for (i = 0; i < mundo->n_herois; i++) {
+					printf("HEROI %2d EXPERIENCIA %2d\n", mundo->herois[i].id, mundo->herois[i].exp);
+					mundo->herois[i].habilidades_do_heroi = destroi_cjt(mundo->herois[i].habilidades_do_heroi);
 				}
-			}
-			int id_local_destino = aleat(0, mundo->n_locais-1);
-			int t_deslocamento = distancia(mundo->locais[id_local], mundo->locais[id_local_destino]) / velocidade_heroi(mundo->herois[id_heroi]);
-			chegada_heroi = { mundo->tempo_atual + t_deslocamento/15, CHEGADA, id_heroi, id_local_destino };
-			adiciona_ordem_lef(lista_de_eventos, &chegada_heroi);
-			break;
-
-		case MISSAO:
-			break;
-		case FIM:
-
-			lista_de_eventos = destroi_lef(lista_de_eventos);
-			break;
-	}
-	/* agenda os novos eventos na lista_de_eventos; */
 
+				for (i = 0; i < mundo->n_locais; i++) {
+					mundo->locais[i].publico = destroi_cjt(mundo->locais[i].publico);
+					mundo->locais[i].fila = destroi_fila(mundo->locais[i].fila);
+				}
+				
+				free(mundo->herois);
+				free(mundo->locais);
+				for (i = 0; i < mundo->n_missoes; i++)
+					if (mundo->missoes[i] != NULL)
+						mundo->missoes[i] = destroi_cjt(mundo->missoes[i]);
+				free(mundo->missoes);
+				mundo->cj_habilidades = destroi_cjt(mundo->cj_habilidades);
+				free(mundo);
+				lista_de_eventos = destroi_lef(lista_de_eventos);
+				break;
+		}
+
+		free(evento_atual);
+	}
 
 	return 0;
 }
-- 
GitLab