Algoritmos e Estruturas de Dados [LEEC] (2024/2025)

Enunciado do Trabalho Prático

[Calendário] [Changelog] [Introdução] [Descrição] [Interface] [Avaliação] [Mooshak] [Erro de Execução] [Observações]


Calendário


Changelog


Introdução

Este enunciado descreve o trabalho prático da disciplina de Algoritmos e Estruturas de Dados do 1º ano da Licenciatura em Engenharia Eletrotécnica e Computadores. Os alunos podem e devem tirar todas as dúvidas com os docentes da disciplina.

O trabalho é para ser realizado por grupos de 2 alunos.

O trabalho tem 2 fases de entrega.

Vão ser realizadas discussões do projeto.

O programa é para ser escrito em ANSI-C (a norma oficial do C), e tem de ser desenvolvido usando a metodologia de programação da disciplina. Note que há alguns aspetos específicos novos que foram apresentados na aula teórica 08.

Pode aproveitar código ou inspirar-se neste pequeno ficheiro: MainSupermercado.c. Ainda, uma implementação completa da coleção História, para quem quiser aproveitar: Registo.h, Registo.c, Historia.h, Historia.c.


Supermercado - compre 1 pelo preço de 2 e leve 1 de graça!

Objetivo

O objetivo deste trabalho é desenvolver um programa para efetuar a gestão de um dia de atividade dum grande supermercado:

Produto

Cada produto é caraterizado por: A designação é uma string sem espaços, mas onde se podem usar hífenes como separadores. Por exemplo, "arroz-risotto-XPTO-extra-475g"; "arroz-carolino-ACME-regular-1kg"; "banana-importada-DEL-VALE"; "banana-da-madeira".

Muitos produtos são vendidos pré-embalados, em pacotes com peso fixo. Por exemplo, pacotes de arroz com 1 kg. Neste caso, a quantidade do produto indica o número de embalagens e o peso unitário diz respeito ao peso da embalagem.

Há produtos que são vendidos avulso, ou seja a peso. Por exemplo, bananas. Neste caso, a quantidade indica o número total de gramas e, além disso, o peso unitário será sempre 1, pois um grama de produto pesa exatamente 1 grama.

Vamos considerar que o peso unitário 1 indica especificamente que o produto é vendido avulso. Não há produtos pré-embalados com peso de 1 grama.

Algum produto que seja vendido pré-embalado, mas em pacotes com peso variável, por exemplo carne pré-embalada, considera-se que está a ser vendido avulso.

Tecnicamente, podem existir produtos disponíveis a custo zero, mas nunca com custo negativo.

Stock

O stock é uma coleção de produtos.

Em cada produto do stock, o campo quantidade indica a quantidade total disponível para venda nas instalações do supermercado.

Há um comando para aumentar o stock dum produto existente e outro comando para criar um produto novo. Também há um comando para listar o estado stock.

Cliente

Cada cliente é caraterizado por: Do ponto de vista do supermercado, os clientes são pessoas anónimas. Contudo, precisamos de ter alguma forma de nos referirmos a um cliente, por exemplo para indicar que um dado cliente escolhe um certo produto, ou para indicar que esse cliente vai para uma certa caixa efetuar o pagamento. Vamos identificar cada cliente usando o número inteiro que indica a sua ordem de chegada ao supermercado, a começar em 0.

A única coisa substancial que precisamos de saber de cada cliente é quais são os produtos que tem no cesto. Por isso, basicamente, "cliente" e "cesto de compras" são a mesma coisa.

O cesto de compras é uma coleção de produtos, onde o campo quantidade de cada produto indica a quantidade que reside no cesto.

Há um comando para colocar um certo número de unidades dum produto no cesto. Se não existir stock suficiente, então deve ser dada a mensagem de erro prevista. Por exemplo, se o cliente precisar de 3 pacotes de arroz e só existirem 2, então a operação falha. O cliente tem sempre a liberdade de pedir 3 pacotes a seguir. Também há um comando para listar o estado dos clientes.

Histórico

Cada registo do histórico é caraterizado por:

Cria-se e adiciona-se um registo histórico sempre que um cliente termina o pagamento.

Depois dum cliente pagar, presume-se que o cliente abandona o supermercado. O objeto que representa o cliente deve ser destruído, incluindo o seu cesto de compras. No histórico, fica a informação resumida atrás indicada.

Há um comando para listar o estado corrente do histórico.

Caixa

Cada caixa é caraterizada por: Em cada caixa, os clientes são processados por ordem de chegada. Quando um cliente chega a uma caixa, já não a abandona mais - vamos assumir isso para simplificar.

O supermercado tem um número de caixas fixo, concretamente 10 caixas. As caixas são numeradas de 0 a 9. O valor 10 deve estar numa constante do programa principal, para ser fácil de alterar.

A caixa zero é especial. Representa a saída do supermercado sem compras e sem qualquer espera. O cliente pode usar a caixa zero apenas se tiver o cesto vazio - se tiver alguma coisa no cesto, nem que seja um produto de custo zero, então terá de usar as outras caixas.

Se o cliente tiver o cesto vazio, o normal será usar a caixa zero - mas o cliente também pode decidir ir para uma caixa normal e aguardar pela sua vez.

O valor mínimo da constante para o número de caixas é 1. No caso de ser usado esse valor mínimo, existirá apenas a caixa 0.

Para simplificar, presume-se que todas as caixas estão permanentemente abertas. Não se prevê a possibilidade duma caixa estar temporariamente fechada.

Há um comando para colocar um cliente numa dada caixa e outro para colocar um cliente na caixa com maior disponibilidade. Também há um comando para listar o estado das caixas.

Na identificação da caixa com maior disponibilidade, em caso de empate escolhe-se a que tiver índice menor.

Tempo

O cliente entra no supermercado e vai enchendo livremente o seu cesto de compras sem restrições de tempo.

A questão do tempo só se coloca na altura do pagamento, nas caixas. Geralmente o cliente olha para as várias caixas e escolhe aquela que lhe parece minimizar o tempo de espera. O tempo de espera depende do número de clientes que está em cada caixa e se têm o cesto mais ou menos cheio.

Nas caixas, o tempo de processamento de cada cliente é o seguinte:

Simulação da passagem do tempo

Existe um comando que faz avançar o tempo um certo número de segundos. O avanço do tempo provoca efeitos em todas as caixas que tenham clientes.

Para o programa ser realista, simula-se paralelismo. Por exemplo, para avançar 100 segundos, visitam-se 100 vezes, circularmente e por ordem, todas as caixas, fazendo avançar cada caixa 1 segundo de cada vez.

Presume-se que durante o avanço do tempo, nenhum cliente novo chega a uma caixa. O avanço do tempo é só para processar os clientes que já estão nas caixas.

O tipo do cliente precisa de ter um campo inteiro tempo, que é preenchido (no momento em que um cliente vai para a caixa) com o tempo de processamento previsto (calcula-se esse tempo na ocasião). Quando um cliente atinge a primeira posição da sua fila e as suas compras estão a processadas, vai-se descontando a passagem do tempo, um segundo de cada vez, nesse campo tempo.

Fecho do supermercado

Quando o supermercado encerra, todos os clientes que estão nas caixas permanecem nas mesmas caixas.

Para os clientes que ainda estão à procura de produtos mas têm o cesto vazio, eles são forcados a ir imediatamente para a caixa 0, pela ordem em que chegaram ao supermercado. ("Ir para a caixa zero" significa abandonar o supermercado no próximo segundo de passagem de tempo.)

Para os clientes que ainda estão à procura de produtos mas já têm alguma coisa no cesto, eles são forcados a ir imediatamente para a caixa 1, onde está um funcionário que faz horas extraordinárias. Esses clientes vão para a caixa 1, pela ordem em que chegaram ao supermercado.

Enquanto houver clientes nas caixas, faz-se passar o tempo continuamente até todos os clientes serem servidos.

O comando de fecho do supermercado deve produzir o seguinte output:


Interface com o utilizador - Comandos

O programa funciona através de comandos introduzidos pelo utilizador. É o utilizador que atualiza o stock, coloca produtor no cesto dum determinado cliente, manda avançar o tempo para os pagamentos nas caixas poderem acontecer, etc.

Nesta secção, damos alguma informação geral sobre os comandos, e listamos os comandos concretos a suportar.

Formatos

Os comandos são pedidos ao utilizador usando o prompt '> '. Cada comando é identificado por uma letra, pode ser dada em maiúsculas ou minúsculas. Por exemplo, o comando de fecho do supermercado pode ser escrito 'f' ou 'F'.

O formato do output dos comandos é rígido, para poder avaliado pelo Mooshak.

Nos exemplos deste documento, todo o texto introduzido pelo utilizador aparece em negrito. Já texto escrito pelo programa aparece de forma normal. Para não haver dúvidas, explicitamos as mudanças de linha usando o símbolo '↩'.

Comandos com erros

1 - Se o utilizador introduzir um comando desconhecido, o programa escreve a mensagem "Comando desconhecido.↩". Por exemplo:

2 - Muitos dos comandos possuem argumentos, que no nosso caso serão sempre strings e números inteiros não negativos. Por favor, assuma que o utilizador introduz sempre uma string onde se espera uma string, e um inteiro onde se espera um inteiro. Por outras palavras, não perca tempo a validar a sintaxe do input do utilizador.

Contudo deverá validar outros aspetos: argumentos a mais ou a menos; valores inteiros negativos; nomes de produto com espaços. Se o utilizador introduzir um comando com um erro destes, o programa escreve a mensagem "Dados invalidos.↩". Por exemplo:

3 - Qualquer outra situação em que o utilizador tente fazer algo de impossível, por exemplo colocar no cesto do cliente múltiplas unidades dum produto com stock insuficiente ou sair por uma caixa que não existe, o programa escreve a mensagem "Nao pode fazer isso.↩".

Há algumas possibilidades relativamente a pedidos impossíveis de concretizar, mas a mensagem de erro é sempre a mesma. Por exemplo:

Os comandos

Eis os comandos a implementar, com indicação se são da fase 1 ou da fase 2:

O texto exato que cada um deste comandos escreve será aqui divulgado daqui a alguns dias.

Exemplo de execução para a fase 1

Os seguintes exemplos de execução servem também para mostrar o formato das mensagens que o programa deve produzir.

Você precisa se seguir rigorosamente estes formatos, porque o seu programa será parcialmente avaliado no Mooshak. Use o concurso do Mooshak que está disponível, para validar esses formatos.

Exemplo de execução para a fase 2 sem usar comandos T e F

Exemplo de execução para a fase 2 usando todos os comandos


Avaliação

Eis como a nota será calculada:

A apreciação da qualidade, inclui pelo menos estes elementos:

Duas fases

Há duas fases de entrega do trabalho (em duas datas diferentes), mas os detalhes não são agora divulgados.

Ainda não há a certeza de qual o peso relativo de cada fase na nota, mas pode garantir-se que a 1ª fase terá um peso maior do que 50%.


Mooshak

O concurso do Mooshak vai começar a receber submissões no dia 16/mai.

Eis os testes públicos da fase1: fase1.zip. Quanto aos testes privados da fase 1, estes só serão conhecidos depois do prazo de entrega.

Eis os testes públicos da fase2: fase2.zip. Quanto aos testes privados da fase 2, estes só serão conhecidos depois do prazo de entrega.

Veja na "antevisão" qual a filosofia de uso do Mooshak e qual é a submissão do seu grupo que será avaliada.


Erro de Execução

Se tem programa a funcionar no seu Windows, mas o Mooshak dá "Erro de Execução", esta secção interessa-lhe.

Os principais casos relatados pelos alunos têm a ver com duas situações (mas poderá haver outras):

O Windows não é muito bom a detetar erros de execução, por exemplo o uso de apontadores indefinidos. O Linux é bastante melhor nisso e o Mooshak está instalado no Linux.

Se não estiver a ver onde está o erro, o ideal seria corrigir o programa usando uma máquina com Linux, por exemplo nos nossos laboratórias.

Está aqui uma alternativa. Submeta neste concurso. O seu programa será executado no Linux usando o teste A10 da primeira fase.

Neste concurso, o resultado é (estranhamente) apresentado sob a forma dum erro de compilação, pois essa é a única forma disponível para o Mooshak comunicar com o utilizador.

Clique no link "Erro de Compilação" para ver as informações. Caso tenha ocorrido um erro de execução no teste A10, verá uma mensagem semelhante à apresentada a seguir.

As linhas que começam por #, representam pela ordem inversa a sequência de chamadas que conduziu ao erro de execução.


Observações


Final

Bom trabalho! Esperamos que goste.