Pontifícia Universidade Católica do Rio Grande do Sul
Faculdade de Informática — Laboratório de Programação II
Trabalho 2 - 2016/2
Data de Entrega: 23/11/2016
Simulação de Comportamento de Robôs
1 Enunciado
O objetivo do trabalho é programar robôs com comportamentos variados. Os
robôs tentam achar a saída de um labirinto como o da figura abaixo:
Quando instanciado, um robô recebe no seu construtor a posição inicial, o ponteiro para um labirinto e a quantidade máxima de passos admitida para tentar sair do labirinto.
Todos os robôs devem ser derivados de uma superclasse abstrata chamada Robo, a qual define alguns métodos que devem ser reimplementados:
class Robo
{
public:
Robo(const Point& posIni, Labirinto* lab, int maxSteps);
virtual void draw() = 0;
void move(const Point& pos) { this->pos = pos; }
virtual void generateSteps() = 0;
vector<Point> getSteps() { return steps; }
protected:
Point posIni;
Labirinto* lab;
int maxSteps;
vector<Point> steps;
};
-
Construtor: recebe a posição inicial, o ponteiro para o labirinto e a quantidade máxima de passos.
-
draw: desenha o robô (veja exemplo em RoboB9.cpp).
-
move: movimenta o robô, ou seja, altera suas coordenadas para a posição recebida por parâmetro.
-
generateSteps: gera a sequência de pontos (Point)
necessária para mover o robô da posição inicial (informada no
construtor) até a posição final, informada como parâmetro. A sequência
depende do algoritmo de movimentação correspondente (veja abaixo).
Observação: considere que um robô saiu do labirinto quando a sua posição estiver fora dos limites do labirinto e que os robôs só se movimentam na horizontal ou vertical.
-
getSteps: retorna a lista de pontos (vector) gerada pelo método generateSteps.
A idéia é criar robôs que tentem sair do labirinto. Para tanto, devem ser implementadas pelo menos duas subclasses de Robo, cada uma com características diferentes:
-
Um robo C3-P0, que se desloca sempre para uma direção (ex:
direita), mas ao colidir em uma parede, gira para o lado direito e tenta
continuar avançando. Se não for possível girar para a sua direita, ele
deve tentar girar para a esquerda. Como não há garantia de saída, este
robô desiste após uma quantidade pré-determinada de passos.
-
Um robô R2-D2, que caminha pelo labirinto mantendo seu braço
esquerdo sempre encostado à parede. Ou seja, ele acompanha a parede
esquerda, para onde esta for. Este robô garantidamente sairá do
labirinto;
- WALL-E, que tenta todos os caminhos possíveis no
labirinto, ou seja, sempre irá sair também. Para tanto, deve ser
construída uma árvore que representa todos os caminhos. A partir dela,
deve ser extraída uma sequência de pontos que leve o robô do ponto
inicial à saída.
Para cada tipo de robô, você deve alterar o código do método draw correspondente, para modificar a figura utilizada no desenho do robô.
A classe RoboB9 implementa um robô cujo movimento é aleatório: use ela para ter dicas de como implementar as funcionalidades das demais.
1.2 Labirinto
Assim como os robôs, um labirinto é definido pela classe abstrata Labirinto:
class Labirinto
{
public:
virtual bool isEmpty(const Point& ponto) = 0;
virtual int getWidth() = 0;
virtual int getHeight() = 0;
virtual int getRobot() = 0;
virtual Point getIniPos() = 0;
virtual void loadMaze(string arquivo) = 0;
};
-
isEmpty: retorna true se a posição passada como parâmetro está vazia.
-
getWidth, getHeight: retorna dimensões do labirinto (largura e altura).
-
getRobot: retorna o tipo de robô lido do arquivo (1, 2 ou 3).
-
getIniPos: retorna a posição inicial para o robô, lida do arquivo.
-
loadMaze: carrega o labirinto para a memória, esse método deve terminar o programa caso não consiga ler corretamente os dados.
Portanto, você deve criar uma classe que implemente os métodos em Labirinto. Isso é necessário para que o labirinto possa ser desenhado corretamente pela interface gráfica (ver abaixo).
O labirinto em si é carregado a partir de um arquivo texto com o seguinte formato:
dim 9 9
pos 1 1
robo 1
*********
* * *
* ***** *
* * * *
* * *** *
* * *
*** * * *
* * *
******* *
Observe que após as informações numéricas vem o desenho do labirinto, feito com * e espaços em branco.
A classe LabirintoTeste implementa um labirinto de teste, que tem apenas paredes nas laterais e uma saída na parte de baixo.
1.3 Interface Gráfica
Para tornar o trabalho mais interessante, está sendo disponibilizada uma classe denominada GL, que implementa uma visualização gráfica do labirinto através de OpenGL. A classe GL deve ser empregada da seguinte forma:
O programa principal inicia com a chamada ao método GL::init, que tem a função de inicializar a biblioteca gráfica e criar a janela da aplicação.
Depois, uma vez realizada a criação dos objetos robô e labirinto, deve ser chamado o método GL::setLabirintoRobo, passando-se como parâmetros o labirinto (ponteiro para um objeto que estenda a classe abstrata Labirinto) e o robô (ponteiro para um objeto que estenda a classe Robo):
GL::setLabirintoRobo(lab, robo);
A seguir, deve ser chamado o método loop, que não retorna:
A partir desse ponto, toda a interação se dá através da classe GL: você NÃO deve chamar os métodos da classe GL de outros pontos do programa.
A interface gráfica chama automaticamente os métodos generateSteps, draw e getSteps do robô desejado, de forma que a interação se dá através dos seguintes comandos:
-
Setas esquerda e direita: avançam e retrocedem um passo na lista de passos obtida pelo método getSteps do robô.
-
ESC: finaliza o programa.
Note também que não se deve criar uma instância de GL para utilizá-la: os métodos são todos static, o que é uma exigência da biblioteca gráfica.
Em resumo, suas tarefas são:
-
Implementar uma classe derivada de Labirinto.
-
Implementar as dua classes derivadas de Robo.
Veja abaixo o resultado do programa de exemplo, que usa uma classe LabirintoTeste.
O zip
robos-base.zip
contém todos os arquivos mencionados anteriormente, bem como alguns
exemplos de labirinto. Há um projeto para Linux, e outro para Windows,
que inclui as bibliotecas necessárias. Se você estiver utilizando uma
máquina pessoal, instale os pacotes
freeglut3-dev e
libjpeg8-dev (no Ubuntu).
2 Critérios de Avaliação
Leia com atenção os critérios de avaliação:
2.1 Funcionamento
-
Carrega e exibe corretamente o labirinto a partir de um arquivo texto (use os arquivos no .zip para testar sua aplicação).
-
Implementa adequamente a lógica de cada tipo de robô.
2.2 Código
-
Toda comunicação com o usuário deve ser realizada através da interface
gráfica, não deve haver entrada nem saída de dados via terminal.
-
A implementação deve seguir as orientações dadas em aula quanto a
convenções C++ para nomes de identificadores e estrutura das classes (ou
seja, nomes de classes começam com letra maiúscula, atributos, métodos e
variáveis em minúsculas).
-
É obrigatório explorar herança e polimorfismo na implementação.
-
O código deve ser indentado (o Code::Blocks FAZ isso). Código não indentado sofrerá descontos na nota.
-
Não serão aceitos trabalhos com erros de compilação. Programas que não compilarem corretamente terão nota ZERO automaticamente.
-
Pontuação:
-
Implementação da leitura do arquivo-texto (classe que estende Labirinto): 2 pontos
-
Implementação do robô C3-PO: 2 pontos
-
Implementação do robô R2-D2: 3 pontos
-
Implementação do robô WALL-E: 2 pontos
-
Uso adequado de orientação a objetos e polimorfismo: 1 pontos
2.3 Entrega
- Os trabalhos pode ser em duplas, ou individuais. Um arquivo
compactado contendo o projeto completo do Code::Blocks deve submetido
pelo Moodle até a data e hora especificadas. O arquivo deve ter o nome e sobrenome dos alunos, da seguinte forma: Nome1Ultimosobrenome_Nome2Ultimosobrenome.zip (ex: AnaMedeiros_JoseSilva.zip). ENVIE APENAS ARQUIVOS .ZIP, ou seja, não envie 7z, rar, tar.gz, tgz, tar.bz2, etc.
-
A nota do trabalho depende da apresentação deste no laboratório, na data
marcada. Trabalhos entregues mas não apresentados terão sua nota
anulada automaticamente. Durante a apresentação será avaliado o domínio
da resolução do problema, podendo inclusive ser possível invalidar o
trabalho quando constatada a falta de conhecimento sobre o código
implementado.
-
A cópia parcial ou completa do trabalho terá como consequência a atribuição de nota ZERO ao trabalho dos alunos envolvidos. A verificação de cópias é feita inclusive entre turmas.