N pistas: Simulação

De Física Computacional
Ir para: navegação, pesquisa
#include<stdio.h>
#include<stdlib.h>
#include<math.h> 


/* declaracao de funcoes */
void passo(FILE *arq);
void inicializacao(FILE *arq);
void atualizar_posicao(void);
int mudar_velocidade(int(v));
int calculo_distancia(void);
int trocar_faixa(void);


/*  declaracao var global   */
#define veloc_max 6
#define tempo_max 50
#define num_carros 60
#define comprimento_rua 60
#define num_faixas 3


/*  velocidade: numero de posições   */
/*  que o carro andará num passo     */

 //precisamos guardar as posicoes anteriores, por isso rua e rua_nova
int rua[num_faixas][comprimento_rua], rua_nova[num_faixas][comprimento_rua], vel[num_carros];

//nao podemos printar assim que mudamos a velocidade do carro, como no caso de uma pista, ja que os carros podem mudar de pista. So podemos printar no final do passo
int print[num_faixas][comprimento_rua];

int prim_carro[num_faixas], dist[num_faixas];
int i, j, k, t, ultimo, k_novo, faz_nada;

//probab_vel = probabilidade de reduzir a velocidade
double probab_vel = 0.3;



void main(void)
{
	
	FILE *arq;
	char nome[30];
	sprintf(nome, "%d_lanes.dat", num_faixas);
	arq = fopen(nome,"w+");

    inicializacao(arq);
	
	for(t = 0; t < tempo_max; t++)
	{	
		passo(arq);		
	}

	fclose(arq);
}



void inicializacao(FILE *arq){

	//srand48(time(NULL));

   	// zerando vetores
   	//-1 significa que a posicao esta vazia

	for(i = 0; i < comprimento_rua; i++){

		for(j = 0; j < num_faixas; j++){

			rua[j][i] = -1;
			rua_nova[j][i] = rua[j][i];
			
		}
	}
	
	//iniciando os carros - rua[k][i] representa o indice do carro, atraves do qual acessaremos sua velocidade em vel[rua[k][i]]
	//da forma como fazemos aqui, iniciamos os carros distribuidos em todas as pistas e equidistantes (aproximadamente)
	k = 0;
	for(i = 0; (i < num_carros) && (k < num_faixas); i++)
	{
		
		vel[i] = 0;	
		
		
		rua[k][(i*comprimento_rua*num_faixas/num_carros) % comprimento_rua] = i;
		rua_nova[k][(i*comprimento_rua*num_faixas/num_carros) % comprimento_rua] = i;
		
		//para trocar de faixa quando a condicao for satisfeita
		if((i+1)*comprimento_rua*num_faixas/num_carros >= comprimento_rua*(k + 1))
		{
			k++;
		}
	}
	
	//printando a condição inicial, no terminal e no arquivo
	for(k = 0; k < num_faixas; k++){
		for (i = 0; i < comprimento_rua; i++){
			if(rua[k][i] == -1){

			printf(".");
			fprintf(arq, "-1 ");
			
			}
			else{
				printf("%d", vel[rua[k][i]]);
				fprintf(arq, "%d ", (vel[rua[k][i]]));
			}
		}	
		printf("\n");
		fprintf(arq, "\n");
	}
	printf("\n");
	fprintf(arq, "\n");
		
}



void passo(FILE *arq)
{
	
	//atualizando a matriz rua, trocando -2 por -1
	for(k = 0; k < num_faixas; k++)
	{
		for(i = 0; i< comprimento_rua; i++)
		{
			if(rua_nova[k][i] == -2)
			{
				rua_nova[k][i] = -1;
			}
			
			rua[k][i] = rua_nova[k][i];
		}

		//para que caso ainda nao haja um primeiro carro, prim_carro assuma um valor que nao se confunda com nenhum indice de carro (que vao de 0 a num_carros)
		prim_carro[k] = -1;
	}
	
	//iterando pela avenida, fixando a posicao ao longo da avenida e variando as pistas
	for(i = 0; i< comprimento_rua; i++)
	{
	
		//calculando a distancia a partir daquela posicao ate o proximo carro, para todas as pistas
		for(k = 0; k < num_faixas; k++)
		{
			dist[k] = calculo_distancia();
		}
	
	
    	for(k = 0; k < num_faixas; k++)
  		{
  			//precisamos de k_novo, ja que o carro pode trocar de pista, mudando seu k
		
  	  		/*  realiza até percorrer todos os carros.  */
    		/*  tem carro na posição 'i'?               */
		
			if (rua[k][i] == -1){	
	
				/*	não, não tem carro em 'i'	*/
				/*	vai pra prox posicao 'i'   	*/
				
				//so printar -1 se o carro anterior nao tiver trocado para essa pista
				if(k_novo != k)
				{
					print[k][i] = -1;
				}
				k_novo = k;
				
			}
			
			else{
				k_novo = k;
	
				/*	caso for o primeiro carro,	*/
				/*	salvar sua posicao para    	*/
				/*	calcularmos a distancia do 	*/
				/*	ultimo carro ao primeiro   	*/

				if(prim_carro[k] == -1){

					prim_carro[k] = i;
				}

				//mudando velocidades
				vel[rua[k][i]] = mudar_velocidade(vel[rua[k][i]]);
				
				/*	           Regra 3              */
				/*	redução de velocidade randomica	*/

				/* fazemos isso aqui por causa da possibilidade de troca de pista: */
				/* ao trocar de pista, o carro vai ter sua velocidade verificada e */
				/* modificada novamente - se a regra 3 estivesse dentro da funcao  */
				/* mudar_velocidade, ela seria aplicada duas vezes nesse caso 	   */
				if( ( vel[rua[k][i]] > 0 ) && ( drand48() < probab_vel )){

					vel[rua[k][i]]--;
				}
			
				//caso k = k_novo, o que conta sera o ultimo comando
				//caso k != k_novo, o primeiro colocara -1 na posicao anterior, e o carro na posicao nova
				print[k][i] = -1;
				print[k_novo][i] = vel[rua[k][i]];
				
				//atualizando posicoes
				atualizar_posicao();

			}	
		}
	}

	//printando
	for(k = 0; k < num_faixas; k++)
	{
		for(i = 0; i < comprimento_rua; i++)
		{
			if(print[k][i] == -1)
			{
				printf(".");
				fprintf(arq, "-1 ");
			}
			else
			{
				printf("%d", print[k][i]);
				fprintf(arq, "%d ", print[k][i]);
			}
			
		}
		
		printf("\n");
		fprintf(arq, "\n");
		
	}
	
	printf("\n");
	fprintf(arq, "\n");
	
}




void atualizar_posicao(void){

	/*	atualiza apenas se a velocidade	*/
	/*	for diferente de zero        	*/
	if(vel[rua[k][i]] != 0){

		//se for o ultimo carro, usamos condicoes de contorno periodicas
		if( i + vel[rua[k][i]] >= comprimento_rua ){

			rua_nova[k_novo][(i+ vel[rua[k][i]]) % comprimento_rua] = rua[k][i];
			
			j = i+1;
			while(j < (i+ vel[rua[k][i]]) % comprimento_rua)
			{
				/* -2 indica o caminho percorrido por um carro (para que nenhum */
				/* outro consiga trocar de pista para essa posicao)				*/
				rua_nova[k_novo][j] = - 2;

				/* caso estejamos na ultima celula, se fizermos j = -1, */ 
				/* no proximo passo j = 0 e voltaremos ao inicio da rua */
				if(j==comprimento_rua - 1)
				{
					j = -1;
				}
				
				j++;
			}
		}
		else{

			rua_nova[k_novo][i + vel[rua[k][i]]] = rua[k][i];
			for(j = i + 1; j < i + vel[rua[k][i]]; j++)
			{
				rua_nova[k_novo][j] = -2;
			}
			
		}

		//-2 indica que havia um carro ali	
		rua_nova[k][i] = -2;
	}
	
	/* caso v=0. mas troque de pista, (ja que pode ser que o carro */
	/* troque de pista com v=1, mas tenha sua velocidade diminuida */
	/* para 0 por causa da Regra 3)								   */
	else if((vel[rua[k][i]] == 0) && (k != k_novo))
	{
		rua_nova[k_novo][i] = rua[k][i];
		rua_nova[k][i] = -2;
	}
				
}




int calculo_distancia(void){

		int x;
		/*	RETORNA A DISTANCIA ENTRE O	*/
		/*	CARRO 'i' E O QUE ESTA NA   */
		/*	SUA FRENTE NA FAIXA 'x'    	*/ 

		/*	caso não for o ultimo carro	*/
		/*	procura posição do prox. e	*/
		/*	calcula a distancia até ele	*/

		/* temos que isolar o caso i = comprimento_rua - 1,*/
		/*	já que j = i + 1 = comprimento_rua, e usamos   */
		/*	rua[j][k], sendo que j < comprimento_rua	   */
		/*												   */
		/*	se i = comprimento_rua - 1, j = comprimento_rua*/
		/*	e j deve ser < comprimento_rua				   */

		//indica o ultimo carro
		ultimo = 0;
		
		if( i + 1 < comprimento_rua )
		{

			j = i + 1;

			while ( rua[k][j] == -1 ){

				if( j == comprimento_rua - 1 ){
					ultimo = 1;
					break;
				}
				j++;	
			}
		
			if ( ultimo == 0 ){

				x = j - i;
			}
			
		}

			/*	para o ultimo carro a distan-	*/
			/*	cia é calculada em relacao ao	*/
			/*	primeiro, pois são C.C. perio-	*/
			/*	dicas.                       	*/
			//aqui devemos tomar cuidado, pois caso a pista esteja vazia, 
			//ultimo = 1, mas nao existe prim_carro[k]. Por isso 
			//definimos prim_carro[k] inicialmente como -1

		else if(i == comprimento_rua - 1)
		{
			ultimo = 1;
		}
		
		//ultimo carro, e existe um primeiro carro (numero de carros > 1)
		if((ultimo == 1) && (prim_carro[k] != -1)){

			x = comprimento_rua - (i - prim_carro[k]);
		}
		
		//caso a pista esteja vazia	ou numero de carros = 1
		else if((ultimo == 1) && (prim_carro[k] == -1))
		{
			x = comprimento_rua;
		}	

		return x;

}




int mudar_velocidade(int(v)){

	int x;
	/*   	RETORNA NOVA VELOCIDADE  	*/	

	/*	            Regra 1         	*/
	/*	caso dê pra acelerar, acelere	*/
	if( ( v < veloc_max ) && ( dist[k_novo] > v + 1 ) ){

		x = v + 1;
	}

	/*	           Regra 2           	*/
	/*	caso pouco espaço, desacelere	*/
	else if( dist[k_novo] < v + 1 ){
		
		//indica se a verificacao de troca de pista resultou em algo
		faz_nada = 0;
		
		//para garantir que um carro que ja trocou de faixa nao entre aqui
		if(k == k_novo)
		{
			//verificacao para trocar de faixa
			x = trocar_faixa();
		}
		//caso o carro ja tenha trocado de faixa
		else
		{
			x = dist[k_novo] - 1;
		}
		
		//se nao deu pra trocar de faixa
		if(faz_nada == 1)
		{
			x = dist[k_novo] - 1;
		}
	}
	
	
	/*Caso em que v=dist-1, ou seja, a velocidade nao se alteraria*/
	else if((dist[k_novo] == v + 1) && (v != veloc_max))
	{
		faz_nada = 0;
		
		//para garantir que um carro que ja trocou de faixa nao entre aqui
		if(k == k_novo)
		{
			x = trocar_faixa();
		}
		//caso o carro ja tenha trocado de faixa
		else
		{
			x = v;
		}
		
		//se nao deu pra trocar de faixa ou se o carro ja trocou de faixa
		if(faz_nada == 1)
		{
			x = v;
		}
	}
	else
	{
		x = v;
	}
	
	return x;
}


int trocar_faixa(void)
{
	int y;	
	
	//tem duas pistas de cada lado
	if((k_novo - 1 >= 0) && (k_novo + 1 < num_faixas))
	{
		//ambas vazias
		if((rua_nova[k_novo-1][i] == -1) && (rua_nova[k_novo+1][i] == -1))
		{
		
			//ambas com mais espaço
			if((dist[k_novo-1] > dist[k_novo]) && (dist[k_novo+1] > dist[k_novo]))
			{
				if(dist[k_novo-1] > dist[k_novo+1])
				{
					k_novo--;
				}
				else if(dist[k_novo+1] > dist[k_novo-1])
				{
					k_novo++;
				}
				//caso dist[k+1]=dist[k-1], escolha aleatoria
				else if(drand48() < 0.5)
				{
					k_novo--;
				}
				else
				{
					k_novo++;
				}
				
				y = mudar_velocidade(vel[rua[k][i]]);
			}
			//so o lado k-1 com mais espaco
			else if(dist[k_novo-1] > dist[k_novo])
			{
				k_novo--;
				
				y = mudar_velocidade(vel[rua[k][i]]);
			}
			//so o lado k+1 com mais espaco
			else if(dist[k_novo+1] > dist[k_novo])
			{
				k_novo++;
				
				y = mudar_velocidade(vel[rua[k][i]]);
			}
			//nenhuma com espaco
			else
			{
				faz_nada = 1;
			}
		}
		//so o lado k-1 vazio
		else if((rua_nova[k_novo-1][i] == -1) && (dist[k_novo-1] > dist[k_novo]))
		{
			k_novo--;
			
			y = mudar_velocidade(vel[rua[k][i]]);
		}
		//so o lado k+1 vazio
		else if((rua_nova[k_novo+1][i] == -1) && (dist[k_novo+1] > dist[k_novo]))
		{
			k_novo++;
		
			y = mudar_velocidade(vel[rua[k][i]]);
		}
		//nenhum lado vazio
		else
		{
			faz_nada = 1;
		}
	}
	//so pista do lado k-1
	else if(k_novo - 1 >= 0)
	{
		//se esta vazia e se ha mais espaco
		if((rua_nova[k_novo-1][i] == -1) && (dist[k_novo-1] > dist[k_novo]))
		{
			k_novo--;
			
			y = mudar_velocidade(vel[rua[k][i]]);
		}
		//nao esta vazia/ sem espaco
		else
		{
			faz_nada = 1;
		}
	}
	//so pista do lado k+1
	else if(k_novo + 1 < comprimento_rua)
	{
		//se esta vazia e se ha mais espaco
		if((rua_nova[k_novo+1][i] == -1) && (dist[k_novo+1] > dist[k_novo]))
		{
			k_novo++;
			
			y = mudar_velocidade(vel[rua[k][i]]);
		}
		//nao esta vazia/sem espaco
		else
		{
			faz_nada = 1;
		}
	}
	else
	{
		faz_nada = 1;
	}
	
	return y;
}