Untitled
unknown
plain_text
a year ago
25 kB
12
Indexable
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#define BUFFER_SIZE 1024
#define DELIMITER " "
int istante_di_tempo;
//Strutture dati
struct ingrediente{
char* nome;
int quantita; // intesa come peso in grammi
struct ingrediente* next;
};
struct ingrediente_lotto {
char*nome;
int quantita;
};
struct lotto{
struct ingrediente_lotto ingr;
int scadenza;
struct lotto* next;
};
struct lotto* magazzino = NULL;
int prossimo_alla_scadenza = 0; // variabile che prende il valore del prossimo elemento a scadere;
struct ricetta{
char* nome;
int in_uso;
int peso;
struct ingrediente* lista_ingredienti;
struct ricetta* next;
};
struct ricetta* ricettario;
struct ordine{
struct ricetta* ricetta_associata;
int istante; // momento in cui l'ordine viene preparato
int num_elementi_oridinati; //stock di elementi dell'ordine
int peso;
char* nome; // nome della ricetta
struct ordine* next;
};
struct ordine* coda_ordini_pronti = NULL; // coda per gli ordini pronti per essere consegnati
struct ordine* prossimo_in_coda_pronti = NULL; // serve per inserimento ordini, politica FIFO
struct ordine* coda_ordini_non_pronti = NULL; // coda per gli ordini pronti non completati
struct ordine* prossimo_in_coda_non_pronti = NULL; // serve per inserimento ordini non pronti, politica FIFO
//funzione per il debug non utile al programma
void stampa_magazzino() {
struct lotto* temp = magazzino;
printf("MAGAZZINO: ");
while(temp!=NULL) {
printf("%s %d %d\t", temp->ingr.nome, temp->ingr.quantita, temp->scadenza);
temp = temp->next;
}
printf("\n");
}
void stampa_ricettario() {
printf("RICETTARIO\n");
for(struct ricetta* p = ricettario; p!=NULL; p=p->next) {
printf("%s: ", p->nome);
for(struct ingrediente* q = p->lista_ingredienti; q!=NULL; q=q->next) {
printf("%s %d, ",q->nome, q->quantita);
}
printf("peso ricetta: %d\n", p->peso);
}
}
void stampa() {
printf("non pronti: ");
if(!coda_ordini_non_pronti) printf("vuota\n");
for(struct ordine* p = coda_ordini_non_pronti; p!=NULL; p=p->next) {
printf("\t%d %s %d peso: %d",p->istante, p->nome, p->num_elementi_oridinati, p->peso);
}
printf("\npronti: ");
if(!coda_ordini_pronti) printf("vuota\n");
for(struct ordine* p = coda_ordini_pronti; p!=NULL; p=p->next) {
printf(" %d %s %d peso: %d",p->istante, p->nome, p->num_elementi_oridinati, p->peso);
}
printf("\n");
}
/*
* Gestione Ordini. Gli ordini vengono preparati all'istante, quindi cerco nel magazzino se ci sono gli ingredienti necessari
* Punto critico 1: Nel magazzino potrebbero esserci più lotti di uno stesso ingrediente, quindi se il primo lotto che incontro
* non basta devo continuare la ricerca, devo ricordarmi però che devo eliminare il lotto se lo finisco. Soluzione brutta: faccio
* prima una funzione che controlla la disponibilità e in caso entro a cancellare. Mi faccio un'altra struttura dati per le
* disponibilità. Statisticamente la seconda è più efficiente sui grandi numeri.
* Quando un ordine viene preparato va messo nella coda per la spedizione
* Quindi ho 2 code, una per la spedizione degli ordini già pronti, ordinata per istante di arrivo ordine
* l'altra invece per preparare gli ordini ordinata per istante di arrivo ordine
*/
struct lotto* elimina_lotto(struct lotto* prec) {
struct lotto* elimina = prec->next;
if(prec == magazzino) {
magazzino = magazzino->next;
free(prec->ingr.nome);
free(prec);
prec = magazzino;
}else {
prec->next = prec->next->next;
free(elimina->ingr.nome);
free(elimina);
}
return prec;
}
int cont = 0;
struct ricetta* trova_ricetta(char* nome) {
struct ricetta* p = ricettario;
cont++;
while (p!=NULL && strcmp(p->nome, nome) != 0) {
p=p->next;
}
return p;
}
void metti_in_coda(struct ordine* nuovo, int flag) {
if(flag == 1) { //mettom in coda non pronti
if(coda_ordini_non_pronti == NULL) {
coda_ordini_non_pronti = nuovo;
prossimo_in_coda_non_pronti = nuovo;
}else {
prossimo_in_coda_non_pronti->next = nuovo;
prossimo_in_coda_non_pronti = nuovo;
}
}else {// metto in coda pronti
//printf("metto in coda pronti %d %s\n", nuovo->istante, nuovo->nome);
if(coda_ordini_pronti == NULL) {
coda_ordini_pronti = nuovo;
prossimo_in_coda_pronti = nuovo;
}else {
prossimo_in_coda_pronti->next = nuovo;
prossimo_in_coda_pronti = nuovo;
}
}
}
void gestione_aggiungi_ordine(char* buffer) {
char* token = strtok(buffer, DELIMITER);
token = strtok(NULL, DELIMITER);
struct ricetta* target = trova_ricetta(token);
if(target == NULL) {
printf("rifiutato\n");
return;
}
printf("accettato\n");
//ora controllo se ho abbastanza ingredienti
//cerco la disponibilità degli ingredienti prima, prestazioni peggiori ma meno spreco di memoria
token = strtok(NULL, DELIMITER);
int num_pezzi = atoi(token);
struct ordine* nuovo = malloc(sizeof(struct ordine));
nuovo->ricetta_associata = target;
target->in_uso++;
nuovo->istante = istante_di_tempo;
nuovo->nome = malloc(strlen(target->nome)+1);
strcpy(nuovo->nome, target->nome);
nuovo->num_elementi_oridinati = num_pezzi;
nuovo->next = NULL;
nuovo->peso = target->peso*num_pezzi;
int quanti=0;
bool disponibile = false;
for(struct ingrediente* p = target->lista_ingredienti; p!=NULL; p=p->next) {
quanti = p->quantita * num_pezzi;
//nuovo->peso += quanti;
//controllo la disponibilità
disponibile = false;
for(struct lotto* q = magazzino; q!=NULL; q=q->next) {
if(strcmp(q->ingr.nome, p->nome) == 0) {
quanti-=q->ingr.quantita;
if(quanti<=0) {
disponibile=true;
break;
}
}
}
if(disponibile == false) {
metti_in_coda(nuovo, 1);
//printf("Mancano ingredienti\n");
return;
}
}
//printf("Ingredienti per l'ordine disponibili\n");
// se sono arrivato qua significa che l'ordine può essere completato
// tolgo dal magazzino gli ingredienti che mi servono e inserisco l'ordine in coda pronti
for(struct ingrediente* p = target->lista_ingredienti; p!=NULL; p=p->next) {
quanti = p->quantita * num_pezzi;
//controllo la disponibilità
struct lotto* prec = magazzino;
for(struct lotto* curr = magazzino; curr!=NULL; curr=curr->next) {
if(strcmp(curr->ingr.nome, p->nome) == 0) {
if(curr->ingr.quantita <= quanti) {
quanti-=curr->ingr.quantita;
curr = elimina_lotto(prec);
}else {
curr->ingr.quantita-=quanti;
quanti = 0;
break;
}
}
prec = curr;
}
}
metti_in_coda(nuovo, 0);
//printf("Aggiustato il magazzino\n");
}
void metti_in_coda_pronti_ord(struct ordine* nuovo) {
if (coda_ordini_pronti == NULL || coda_ordini_pronti->istante >= nuovo->istante) {
nuovo->next = coda_ordini_pronti;
coda_ordini_pronti = nuovo;
if(coda_ordini_pronti == NULL) prossimo_in_coda_pronti = NULL;
} else {
struct ordine* corrente = coda_ordini_pronti;
while (corrente->next != NULL && corrente->next->istante < nuovo->istante) {
corrente = corrente->next;
}
nuovo->next = corrente->next;
corrente->next = nuovo;
if(nuovo->next == NULL) prossimo_in_coda_pronti = nuovo;
}
if (nuovo->next == NULL) {
prossimo_in_coda_pronti = nuovo;
}
}
/*
* La funzione per controllare gli ordini non pronti è sbagliata, per correggerla rileggila tutta e cerca di dividere in funzioni in modo da renderla leggibile.
* Il probleme è che dopo che non inserisce il primo elemento disponibi=false e non rientra più nel ciclo smettendo di controllare. Bisogna capire come far ciclare
* il ciclo while
*/
bool aggiorna_ordine_non_pronto(struct ordine* check) {
struct ricetta* target = check->ricetta_associata;
struct lotto* vettore[50];
int vettore_quantita[50];
if(magazzino==NULL) return false; // spostare al chiamante
int ind = 0;
int quanti =0;
bool disponibile = false;
//stampa_magazzino();
for(struct ingrediente* p = target->lista_ingredienti; p!=NULL; p=p->next) {
disponibile = false;
quanti = check->num_elementi_oridinati * p->quantita;
for(struct lotto* q = magazzino; q !=NULL; q=q->next) {
if(strcmp(p->nome, q->ingr.nome) == 0) {
vettore_quantita[ind] = quanti;
quanti-=q->ingr.quantita;
vettore[ind] = q;
if(quanti<=0) { //lotto da eliminare e rompo il ciclo
disponibile = true;
ind++;
break;
}
vettore_quantita[ind] = q->ingr.quantita;
ind++;
}
}
if(disponibile == false) { //Un ingrediente non è sufficiente
if(istante_di_tempo == 33) {
printf("%d %s Manca il %s\n", check->istante, check->nome, p->nome);
}
return false;
}
}
//Ora mi occupo di aggiornare il magazzino
for(int i=0; i<ind && magazzino; i++){ //controllo su magazzino ridondante, so che ci sono i lotti da eliminare prima che il magazzino diventi null
if(vettore[i]->ingr.quantita == vettore_quantita[i]) { //lotto da eliminare
if(vettore[i] == magazzino) {
magazzino = magazzino->next;
prossimo_alla_scadenza = magazzino->scadenza;
free(vettore[i]->ingr.nome);
free(vettore[i]);
}else {
struct lotto* prec = magazzino;
for(struct lotto* p = magazzino; p!=NULL; p=p->next) {
if(p == vettore[i]) { //trovato il lotto
struct lotto* del = p;
prec->next = p->next;
free(del->ingr.nome);
free(del);
p = prec;
}
prec = p;
}
}
}else { //lotto da aggiornare
vettore[i]->ingr.quantita -= vettore_quantita[i];
}
}
return true;
}
void controllo_ordini_non_pronti() {
struct ordine* prec = coda_ordini_non_pronti;
if(magazzino == NULL) return;
bool testa = false;
for(struct ordine* p = coda_ordini_non_pronti; p!=NULL; p=p->next) {
if(testa == true) p = coda_ordini_non_pronti;
testa = false;
bool ret = aggiorna_ordine_non_pronto(p);
if(ret == true) {//devo spostare l'ordine
if(p==coda_ordini_non_pronti) { //elimino dalla testa
coda_ordini_non_pronti = coda_ordini_non_pronti->next;
metti_in_coda_pronti_ord(p);
p = coda_ordini_non_pronti;
testa = true;
}else {
prec->next = p->next;
metti_in_coda_pronti_ord(p);
p = prec;
if(p->next == NULL) {//sono in coda
prossimo_in_coda_non_pronti = p;
}
}
}
prec = p;
}
if(coda_ordini_non_pronti == NULL) prossimo_in_coda_non_pronti =NULL;
}
/*
void controllo_ordini_non_pronti() {
struct lotto* vettore[50]; // indici dei lotti da svuotare
int vettore_quantita[50]; // quantita di ingredienta da eliminare per lotto
bool disponibile = true;
struct ordine* ord_prec = coda_ordini_non_pronti;
struct ordine* ord = coda_ordini_non_pronti;
while(ord) {
struct ricetta* target = ord->ricetta_associata;
int quanti = 0;
int ind = 0;
for(struct ingrediente* p = target->lista_ingredienti; p!=NULL; p=p->next) {
quanti = p->quantita * ord->num_elementi_oridinati;
//controllo la disponibilità
disponibile = false;
for(struct lotto* q = magazzino; q!=NULL; q=q->next) {
if(strcmp(q->ingr.nome, p->nome) == 0) {
vettore_quantita[ind] = quanti;
quanti-=q->ingr.quantita;
vettore[ind] = q;
if(quanti<=0) {
disponibile=true;
//printf("\t%d %s disponibile per %s\n",p->quantita * ord->num_elementi_oridinati, q->ingr.nome, ord->nome);
ind++;
break;
}else {
vettore_quantita[ind] = q->ingr.quantita;
//printf("\t%d %s NON disponibile per %s\n",p->quantita * ord->num_elementi_oridinati, q->ingr.nome, ord->nome);
}
ind++;
}
}
if(disponibile == false) {
//printf("Non aggiunto alla coda pronti %d %s\n", ord->istante, ord->nome);
break;
}
}
if (disponibile && magazzino != NULL) {
struct ordine* da_eliminare = ord;
if (ord == coda_ordini_non_pronti) {
coda_ordini_non_pronti = ord->next;
} else {
ord_prec->next = ord->next;
}
ord = ord->next;
metti_in_coda_pronti_ord(da_eliminare);
// Aggiornamento del magazzino
for (int i = 0; i < ind; i++) {
if (vettore_quantita[i] == vettore[i]->ingr.quantita) {
if (vettore[i] == magazzino) {
magazzino = magazzino->next;
} else {
struct lotto* prec = magazzino;
while (prec->next != vettore[i]) {
prec = prec->next;
}
prec->next = vettore[i]->next;
}
free(vettore[i]->ingr.nome);
free(vettore[i]);
} else {
vettore[i]->ingr.quantita -= vettore_quantita[i];
}
}
} else {
ord_prec = ord;
ord = ord->next;
}
if (coda_ordini_non_pronti == NULL) {
prossimo_in_coda_non_pronti = NULL;
}
}
}
*/
/*
* Gestione ricette. Appena arriva una nuova ricetta da inserire devo controllare che non sia già presente. In caso mi non aggiungo
* Per ottimizzare l'inserimento, visto che non si può predirre la ricerca, inserisco sempre in testa.
*/
void gestione_aggiungi_ricetta(char* buffer) {
struct ingrediente *temp;
char* token = strtok(buffer, DELIMITER);
token = strtok(NULL, DELIMITER);
if(trova_ricetta(token) != NULL){
printf("ignorato\n");
return;
}
struct ricetta* nuova_ricetta = malloc(sizeof(struct ricetta));
nuova_ricetta->nome = malloc(strlen(token)+1);
strcpy(nuova_ricetta->nome, token);
nuova_ricetta->in_uso = 0;
nuova_ricetta->next = NULL;
nuova_ricetta->lista_ingredienti = NULL; //inizialmente vuota
nuova_ricetta->peso = 0;
while((token = strtok(NULL, DELIMITER)) != NULL) { //prelevo il nome dell'ingrediente
temp = malloc(sizeof(struct ingrediente));
temp->nome = malloc(strlen(token)+1);
strcpy(temp->nome, token);
token = strtok(NULL, DELIMITER); //quantita ingrediente
temp->quantita = atoi(token);
nuova_ricetta->peso += temp->quantita;
temp->next = NULL;
temp->next = nuova_ricetta->lista_ingredienti;
nuova_ricetta->lista_ingredienti = temp;
}
nuova_ricetta->next = ricettario;
ricettario = nuova_ricetta;
printf("aggiunta\n");
//stampa_ricettario();
}
//Funzione che inserisce nella lista ordinato in modo crescente per scadenza
void inserisciLottoOrdinato(struct ingrediente_lotto ingr, int scadenza) {
struct lotto* nuovo = malloc(sizeof(struct lotto));
nuovo->ingr = ingr;
nuovo->scadenza = scadenza;
nuovo->next = NULL;
if(prossimo_alla_scadenza == 0)
prossimo_alla_scadenza = scadenza;
if(magazzino==NULL || magazzino->scadenza>=scadenza) {
nuovo->next = magazzino;
magazzino = nuovo;
}else{
struct lotto* corrente = magazzino;
while (corrente->next != NULL && corrente->next->scadenza < scadenza) {
corrente = corrente->next;
}
nuovo->next = corrente->next;
corrente->next = nuovo;
}
}
void elimina_lotti_scaduti(int scadenza) {
//printf("Elimino i lotti scaduti all'istante %d\n", scadenza);
struct lotto* curr = magazzino;
while(magazzino != NULL && curr->scadenza == scadenza) {
magazzino = magazzino->next;
free(curr->ingr.nome);
free(curr);
curr = magazzino;
}
if(magazzino)
prossimo_alla_scadenza = magazzino->scadenza;
else
prossimo_alla_scadenza = 0;
}
void gestione_rifornimento(char* buffer) {
//mi aspetto un input del tipo nome_prodotto + quantità + data scadenza quindi devo fare 3 strtok
//non faccio controlli perché l'affidabilità dell'input è garantita da specifiche
char* token = strtok(buffer, DELIMITER); // la prima parola è il comando e la scarto
while((token = strtok(NULL, DELIMITER)) != NULL) { // quando è NULL significa che ho terminato la lettura
struct ingrediente_lotto temp;
temp.nome = malloc(strlen(token)+1);
strcpy(temp.nome, token);
char* aux = strtok(NULL, DELIMITER);
if(aux==NULL) { break;}
temp.quantita = atoi(aux); //quantita
//printf("\tInserisco ingrediente %s %d\n", temp.nome, temp.quantita);
aux = strtok(NULL, DELIMITER);
if(aux==NULL) { break;}
int scadenza = atoi(aux);
//printf("%s %d %d\n", temp.nome, temp.quantita, scadenza);
inserisciLottoOrdinato(temp, scadenza);
}
printf("rifornito\n");
//stampa_magazzino();
if(coda_ordini_non_pronti) controllo_ordini_non_pronti();
prossimo_alla_scadenza = magazzino->scadenza;
}
/*
* Per rimuovere una ricetta devo eliminare anche tutti gli ingredienti dalla lista, devo ricordarmi che nella lista le stringhe
* sono allocate in memoria dinamica
*/
void gestione_rimuovi_ricetta(char* buffer) {
buffer[strlen(buffer)-1] = '\0'; //mi serve per eliminare il carattere di fine stringa
strcpy(buffer, buffer+16);
struct ricetta* corrente = ricettario;
struct ricetta* precedente = NULL;
while (corrente != NULL && strcmp(corrente->nome, buffer) != 0) {
precedente = corrente;
corrente = corrente->next;
}
if (corrente == NULL) {
printf("non presente\n");
return;
}
if(corrente->in_uso != 0) {
printf("ordini in sospeso\n");
return;
}
//Prima aggiusto il ricettario, poi libero la memoria
if (precedente == NULL) ricettario = corrente->next;
else precedente->next = corrente->next;
free(corrente->nome); // libero il nome della ricetta
// Dealloca la lista degli ingredienti
struct ingrediente* ingr_corrente = corrente->lista_ingredienti;
while (ingr_corrente != NULL) {
struct ingrediente* ingr_da_rimuovere = ingr_corrente;
ingr_corrente = ingr_corrente->next;
free(ingr_da_rimuovere->nome);
free(ingr_da_rimuovere);
}
free(corrente);
printf("rimossa\n");
}
/*
* Quando arriva un corriere devo prendere gli ordini pronti a partire dalla testa e inserirli in una lista ordinata per
* peso, in quell'ordine vanno caricati nel corriere
*/
struct ordine* carico = NULL;
//La funzione inserisce in una lista ordinata per peso, in caso di pesi uguali ordina per istante
void inserisci_carico(struct ordine* ord) {
ord->next = NULL;
if(carico==NULL || (ord->peso > carico->peso) || (ord->peso == carico->peso && ord->istante < carico->istante)) {
ord->next = carico;
carico = ord;
}else {
struct ordine* corrente = carico;
while(corrente->next != NULL && (
(corrente->next->peso>ord->peso) ||
(corrente->next->peso == ord->peso && corrente->next->istante < ord->istante)
)){
corrente = corrente->next;
}
ord->next = corrente->next;
corrente->next = ord;
}
}
void gestione_corriere(int capienza) {
//printf("Camioncino arrivato\n");
//stampa();
if(coda_ordini_pronti == NULL) {
printf("camioncino vuoto\n");
return;
}
while(coda_ordini_pronti != NULL && capienza >= coda_ordini_pronti->peso) {
capienza-=coda_ordini_pronti->peso;
struct ordine* del = coda_ordini_pronti;
coda_ordini_pronti = coda_ordini_pronti->next;
if(coda_ordini_pronti == NULL) {
prossimo_in_coda_pronti = NULL;
}
inserisci_carico(del);
}
while (carico!=NULL) {
printf("%d %s %d\n", carico->istante, carico->nome, carico->num_elementi_oridinati);
struct ordine* del = carico;
carico = carico->next;
del->ricetta_associata->in_uso--;
free(del->nome);
free(del);
}
}
/*
* Da FARE: implementare la rimozione degli ordini non pronti dopo un rifornimento
* implementare la non rimozione di una ricetta se ci sono ordini da completare con quella ricetta
* e stampa ordini in sospeso, provare aggiungenod un id alla ricetta, così da non fare mille strcmp
*
*/
int main() {
int periodicita = 0;
int capienza_corriere=0;
char *buffer = malloc(BUFFER_SIZE);
//printf("INIZIAMO\n");
if (buffer == NULL) {
perror("Unable to allocate buffer");
exit(1);
}
//Per prima cosa leggo i due interi di inizio file
if(fgets(buffer, BUFFER_SIZE, stdin)) {
//printf("Il buffer e: %s\n", buffer);
sscanf(buffer, "%d %d", &periodicita, &capienza_corriere);
//printf("Prima riga %d %d \n", periodicita, capienza_corriere);
}else {
return 0;
}
/*
* Ora inizio a leggere le righe del file, tenendomi un contatore
* Quando il contatore contiene un valore multiplo della periodicità allora
* significa che è arrivato un corriere
*/
istante_di_tempo = 0;
while (fgets(buffer, BUFFER_SIZE, stdin)){
//stampa();
printf("%d ", istante_di_tempo);
if(istante_di_tempo%periodicita == 0 && istante_di_tempo!=0) {
//printf("Arrivato un corriere\n");
gestione_corriere(capienza_corriere);
}
if(istante_di_tempo == prossimo_alla_scadenza)
elimina_lotti_scaduti(istante_di_tempo);
//printf("Hai inserito: %s", buffer);
if (strncmp(buffer, "rifornimento", 12) == 0) {
//printf("Esegui comando rifornimento\n");
//stampa_magazzino();
gestione_rifornimento(buffer);
} else if (strncmp(buffer, "ordine", 6) == 0) {
//printf("Esegui comando ordine\n");
gestione_aggiungi_ordine(buffer);
//stampa();
} else if (strncmp(buffer, "rimuovi_ricetta", 15) == 0) {
//printf("Esegui comando rimuovi_ricetta\n");
gestione_rimuovi_ricetta(buffer);
} else if (strncmp(buffer, "aggiungi_ricetta", 16) == 0) {
//printf("Esegui comando aggiungi_ricetta\n");
gestione_aggiungi_ricetta(buffer);
//stampa_ricettario();
} else {
printf("Comando non riconosciuto\n");
}
istante_di_tempo++;
/*printf("*******************************************\n");
stampa_magazzino();
stampa_ricettario();
stampa();
printf("*******************************************\n");
*/
//stampa();
}
if(istante_di_tempo%periodicita == 0 && istante_di_tempo!=0) {
//printf("Arrivato un corriere\n");
gestione_corriere(capienza_corriere);
}
free(buffer); // Libera la memoria allocata
return 0;
}
Editor is loading...
Leave a Comment