Untitled
#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; }
Leave a Comment