Aula Prática 8

Prazo de entrega: 1 semana (conferir no Moodle)

Exercício 1: Rede Social

Pede-se para implementar um simulador de redes sociais na linguagem C. Este simulador deve ser compilado em um módulo de nome redesocial, que consiste de dois arquivos:

Somente esses dois arquivos devem ser submetidos!

Esse procedimento permite que a correção do exercício seja feita de forma automática. O professor desenvolveu um programa que usa e testa todas as funções do módulo redesocial. Assim, se o módulo contiver funções com nomes diferentes daqueles propostos nos exercícios ou o módulo não for entregue, não será possível avaliar o exercício.

Importante: no final deste documento há a implementação do arquivo redesocial.h, do arquivo pratica8rs.c, que contém o procedimento main(), além de um protótipo do arquivo redesocial.c. Para mais informações sobre como gerar um módulo, consulte os slides da Aula 3 publicada no site da disciplina.

Problema

Uma rede social de amizades pode ser representada por um grafo \(G(V,E)\) em que \(V\) é o conjunto de nós e \(E\) o conjunto de arestas do mesmo. Cada um dos nós \(n_0, n_1,n_2...\) representa uma pessoa e, caso duas pessoas \(n_i\) e \(n_j\) sejam amigas, existe uma aresta \((i,j) \in E\). Umas das maneiras usuais para se representar um grafo é através de uma matriz de adjacência \(n \times n\) de \(n\) colunas e \(n\) linhas. Cada linha (ou coluna) \(i\) contém as relações da pessoa \(n_i\). Considere a matriz de adjacência abaixo:

ID \(n_0\) \(n_1\) \(n_2\) \(n_3\) \(n_4\)
\(n_0\) 0 1 1 0 1
\(n_1\) 1 0 0 1 0
\(n_2\) 1 0 0 0 0
\(n_3\) 0 1 0 0 1
\(n_4\) 1 0 0 1 0

Esta matriz representa uma rede social entre 5 pessoas: \(n_0,n_1,n_2,n_3\) e \(n_4\). Além disso, quando a posição \((i,j)\) da matriz é \(1\), então as pessoas \(n_i\) e \(n_j\) são amigas entre si. Caso a posição \((i,j)\) da matriz é \(0\), então \(n_i\) e \(n_j\) não são amigas. Observe que a pessoa \(n_0\) é amiga das pessoas \(n_1, n_2\) e \(n_4\), mas não é amiga da pessoa \(n_3\).

Importante: a relação de amizade é simétrica: se \(n_i\) é amigo de \(n_j\), então \(n_j\) é, necessariamente, amigo de \(n_i\). Além disso, em redes sociais de amizade, não existe aresta entre a mesma pessoa, ou seja, não existem arestas do tipo \((i,i)\).

Nesta prática, considere que você vai implementar um simulador de redes sociais de amizade usando uma matriz de adjacência. O número de pessoas da rede social é definido na constante NUM_PESSOAS do arquivo redesocial.h. A matriz de adjacência é a variável global M[NUM_PESSOAS][NUM_PESSOAS], declarada no arquivo redesocial.c. Uma variável global pode ser usada em qualquer parte do arquivo em que ela foi declarada sem a necessidade de passá-la como parâmetro. Neste exercício, considere que as pessoas da rede social podem ser identificadas pelos inteiros 0, 1, 2, ..., NUM_PESSOAS-1.

Exercícios

Todos os exercícios a seguir devem ser implementados no arquivo redesocial.c.

  1. Implementar um procedimento para inicializar a matriz de adjacência que gerencia a rede social. Inicialmente, ninguém é amigo de ninguém, ou seja, todas as posições da matriz são zeradas. Protótipo:
void inicializar_rede();
  1. Implementar um procedimento para marcar duas pessoas como amigas na matriz de adjacência. Protótipo:
void adicionar_amizade(int i, int j);

Observações: Lembre que a relação de amizade é simétrica!

  1. Implementar uma função que retorna um número aleatório de tipo ponto flutuante entre 0 e 1. Dica: o maior número aleatório gerado pela função rand() é definido pela constante RAND_MAX, que por sua vez é definida na biblioteca stdlib.h. Protótipo:
float random_float();
  1. Implementar um procedimento para criar uma rede social aleatória a partir de um único parâmetro \(P \in [0,1]\). Para cada par de pessoas \((i,j)\), este procedimento deve gerar um número aleatório de tipo ponto flutuante \(r\) entre \(0\) e \(1\) (ex: 0.2345). Caso \(r\) seja menor que \(P\), então deve-se criar uma amizade entre as pessoas \(n_i\) e \(n_j\). Exemplo: se \(P=0.8\), para o par de pessoas \(n_0\) e \(n_1\), se o número \(r\) gerado for \(0.5412\), então você deve criar uma amizade entre essas pessoas. Protótipo:
void popularRedeSocialAleatoriamente(float P);

Observações: Lembre que a relação de amizade é simétrica, ou seja, se você testou o par \((i,j)\) então você não deve testar o par \((j,i)\). Lembre também que uma pessoa não pode ser amiga dela mesma. Dica: use as funções adicionar_amizade e random_float.

  1. Implementar um procedimento para imprimir a matriz de adjacência de uma rede social. Protótipo:
void imprimirRedeSocial();
  1. Implementar uma função para retornar o número de amigos em comum que duas pessoas têm. Essa função deve também imprimir os identificadores dos amigos em comum.
int numAmigosEmComum(int v, int u);
  1. DESAFIO PARA OS (MUITO) FORTES: Implementar uma função para calcular o coeficiente de aglomeração de uma pessoa. Protótipo:
float coeficienteAglomeracao(int v);

O coeficiente de aglomeração de um nó \(i\) em um grafo é a probabilidade de dois amigos de \(i\) serem também amigos entre si. Ele é calculado da seguinte maneira:

  1. Conte o número \(n\) de amigos de \(i\).
  2. Crie um contador \(cont\) e o inicialize com \(0\).
  3. Para cada amigo \(u\) de \(i\), conte quantos amigos \(v\) de \(i\) também é amigo de \(u\), lembrando que \(u \neq v\). Adicione essa contagem à \(cont\).
  4. O coeficiente de aglomeração é o quociente da divisão entre \(cont\) e o número máximo possível de amizades entre os \(n\) amigos de \(i\), dado por \(n \times (n-1) / 2\).
  5. O coeficiente de aglomeração deve ser um número entre 0 e 1.

Arquivos

redesocial.h redesocial.c pratica8rs.c

Exercício 2: The Elder Scrolls: Algorithms

Neste exercício, você deve criar um protótipo de um sistema de batalha entre guerreiros de um jogo. Para isso, implemente os itens a seguir em um módulo separado chamado jogo.

  1. Defina um novo tipo de dados chamado Guerreiro seguintes campos: ataque (inteiro), defesa (inteiro), pontos_vida (inteiro) e id_jogador (inteiro).

  2. Escreva uma função de nome rolaDados que simula a rolagem de três dados de seis faces tradicionais (1 a 6) e retorna a soma dessas rolagens. Note que somar os valores resultantes da rolagem de três dados de seis faces é diferente de rolar um dado que retorna um número entre 3 e 18.

  3. Escreva um procedimento de nome criaGuerreiro que recebe um Guerreiro por passagem de parâmetro por referência e que atribui valores aos seus campos de batalha. Os seus campos de batalha (ataque e defesa devem receber um valor inteiro da função rolaDados). O campo pontos_vida deve receber a soma dos valores retornados por três execuções da função rolaDados.

  4. Escreva um procedimento de nome ataca que recebe dois Guerreiros por passagem de parâmetro por referência e simula um ataque do primeiro guerreiro no segundo. O ataque é dado da seguinte maneira:

  1. Escreva um programa que simula a batalha até a morte entre dois guerreiros. Para isso, crie dois guerreiros, um com id_jogador 1 e outro com id_jogador 2. Depois, atribua valores aleatórios para os seus campos de batalha a partir da função criaGuerreiro e inicie ataques intercalados entre esses guerreiros, ou seja, comece com o guerreiro 1 atacando o 2, depois o 2 atacando o 1, depois o 1 atacando o 2 e assim por diante. Para simular um ataque, use a função ataca. A batalha deve acabar quando um dos jogadores, o perdedor, alcançar 0 ou menos pontos_vida. Imprima na tela o identificador do guerreiro vencedor. Este exercício deve usar o módulo jogo criado no exercício anterior e deve ser implementado no arquivo testajogo.c.

  2. DESAFIO PARA OS FORTES. Escreva um programa que simula um campeonato entre 16 guerreiros. Este campeonato deve ser do tipo mata-mata, ou seja, eliminatório. Na primeira rodada, simule 8 batalhas entre os 16 guerreiros, em que o guerreiro 1 enfrenta o 2, o 3 enfrenta o 4, e assim por diante. Depois, simule batalhas entre os vencedores dos confrontos, ou seja, o vencedor do confronto 1 enfrenta o vencedor do confronto 2, o vencedor do confronto 3 enfrenta o vencedor do confronto 4, e assim por diante. Repita esse procedimento até chegar no campeão. Imprima o seu identificador e a sua quantidade de pontos de vida. Este exercício deve usar o módulo jogo criado no exercício anterior e deve ser implementado no arquivo testacampeonato.c.

-- Profs. Pedro O. S. Vaz de Melo e Ítalo F. S. Cunha

! vim: tw=68