TP8: bieres
This commit is contained in:
303
TP8/Bieres/main.cpp
Normal file
303
TP8/Bieres/main.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Biere {
|
||||
string nom;
|
||||
string type;
|
||||
float deg_alcool;
|
||||
float prix;
|
||||
string region;
|
||||
|
||||
public:
|
||||
void saisie(ifstream& stream);
|
||||
// Saisie (mais depuis le clavier)
|
||||
void saisie();
|
||||
void affichage();
|
||||
|
||||
float get_deg_alcool() {
|
||||
return deg_alcool;
|
||||
}
|
||||
float get_prix() {
|
||||
return prix;
|
||||
}
|
||||
|
||||
string get_nom() {
|
||||
return nom;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Ici la fonction lecture n'est pas une template
|
||||
// car il doit ajouter au bon conteneur en fonction du type de bière
|
||||
// On aurait pu aussi imaginer une template, avec un "filtre", qui n'ajoute que
|
||||
// dans le conteneur passé en paramètre si le type == filtre.
|
||||
// Mais cela aurait nécessité 2lectures du fichier (ou une autre fonction)
|
||||
void lecture_fichier(list<Biere>& belges, vector<Biere>& etrangeres, const string fname) {
|
||||
ifstream file(fname);
|
||||
|
||||
if (!file.is_open()) {
|
||||
cout << "Erreur lors de l'ouverture du fichier" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
while (!file.eof()) {
|
||||
string type;
|
||||
Biere b;
|
||||
|
||||
getline(file,type, ';');
|
||||
b.saisie(file);
|
||||
|
||||
if (type == "Belge") {
|
||||
belges.push_back(b);
|
||||
}
|
||||
else {
|
||||
etrangeres.push_back(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// La version template
|
||||
// En soit le 2e paramètre (T) n'est pas vraiment nécessaire parce que toujours = "Biere"
|
||||
// j'ai aucune idée de si il faut le mettre ou pas c'est un peu coup de poker avec
|
||||
// Benjelloun, il peut te dire fallait pas le mettre pour la raison que j'ai cité ci-dessus
|
||||
// mais aussi te dire mais il fallait le mettre (si on envisage l'inhéritance d'une classe bière)
|
||||
template <class C, class T>
|
||||
void lecture_fichier_filtre(C& conteneur, const string type, const string fname) {
|
||||
ifstream file(fname);
|
||||
|
||||
if (!file.is_open()) {
|
||||
cout << "Erreur lors de l'ouverture du fichier" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
while (!file.eof()) {
|
||||
string t;
|
||||
|
||||
getline(file, t, ';');
|
||||
if (t != type) {
|
||||
file.ignore(200, '\n'); // passer la ligne, count=200 s'arrête dès que '\n'.
|
||||
continue;
|
||||
}
|
||||
|
||||
T b;
|
||||
b.saisie(file);
|
||||
|
||||
conteneur.push_back(b);
|
||||
}
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void affichage(C& c) {
|
||||
for (auto& a : c) {
|
||||
a.affichage();
|
||||
}
|
||||
}
|
||||
|
||||
string saisie_type_biere() {
|
||||
string t;
|
||||
cout << "Belge ou pas (O/N) :";
|
||||
cin >> t; cin.ignore();
|
||||
return t == "O" ? "Belge" : "Etranger";
|
||||
}
|
||||
|
||||
// Pareil ici pour le type T = "Biere"
|
||||
// j'aime beacoup la syntaxe
|
||||
// using T = typename C::value_type
|
||||
// qui évite de devoir passer T explicitement
|
||||
// mais pas sur que les assistants connaissent tous/ benjelloun apprécie
|
||||
template <class C, class T>
|
||||
void ajout(C& conteneur) {
|
||||
T b;
|
||||
b.saisie();
|
||||
conteneur.insert(conteneur.begin(), b);
|
||||
}
|
||||
|
||||
void saisie_seuil(int& s) {
|
||||
cout << "Seuil : ";
|
||||
cin >> s;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void erase_seuil_alcool(C& cont, float seuil) {
|
||||
// au lieu d'itérer on aurait aussi pu utiliser remove_if (<algorithm>)
|
||||
// mais à lors il aurait fallut passer le "seuil" en paramètre avec l'équivalent
|
||||
// d'un "higher order function" ou d'un lambda
|
||||
// mais pas vu au cours donc on fait comme ça.
|
||||
|
||||
auto it = cont.begin();
|
||||
for (; it != cont.end(); /* il ne faut pas incrémenter l'itérateur à chaque fois, si on supprime on skip l'élement */) {
|
||||
// it-> est équivalent à une déréférence (*it)
|
||||
if (it->get_deg_alcool() >= seuil) {
|
||||
it = cont.erase(it);
|
||||
}
|
||||
else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// T= tjr bière en soit
|
||||
template <class T>
|
||||
bool comparer_prix(T& a, T& b) {
|
||||
return a.get_prix() < b.get_prix();
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void plus_cher(C& cont) {
|
||||
// pour obtenir les bières LES + chers ont peu soit
|
||||
// itérer pour récupérer le max() en prix
|
||||
// puis réitéré et n'afficher que les bières ou
|
||||
// prix == max
|
||||
// ou sort le conteneur O(N logN) puis prendre les N premier
|
||||
// tant que N == prixPrecedent.
|
||||
|
||||
// max_element marchera pas pour PLUSIEURS bières :(
|
||||
auto it = max_element(cont.begin(), cont.end(), comparer_prix<Biere>);
|
||||
|
||||
if (it == cont.end()) {
|
||||
cout << "Aucune bière dans le conteneur";
|
||||
return;
|
||||
}
|
||||
|
||||
// équivalent à (*it).get_prix();
|
||||
float prixMax = it->get_prix();
|
||||
|
||||
for (auto& b : cont) {
|
||||
if (b.get_prix() == prixMax) {
|
||||
// b.affichage();
|
||||
cout << b.get_nom() << " au prix de " << setprecision(4) << b.get_prix() << " euros" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int menu() {
|
||||
int choix;
|
||||
cout << "1. Stocker les bières Belge(s) dans une List et les bières Etrangere(s) dans un Vector + Afficher" << endl
|
||||
<< "2. Ajouter au début une bière à List ou au Vector des bières selon si la bière est Belge ou pas" << endl
|
||||
<< "3. Supprimer les bières dont le degré d'alcool est supérieure à un seuil donné par l’utilisateur" << endl
|
||||
<< "4. Afficher les bières les plus chères du List et du Vector" << endl;
|
||||
|
||||
cout << "Choix:" << endl;
|
||||
cin >> choix;
|
||||
return choix;
|
||||
}
|
||||
|
||||
int main() {
|
||||
list<Biere> belges;
|
||||
vector<Biere> etrangeres;
|
||||
|
||||
int seuil;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
while (true) {
|
||||
switch (menu()) {
|
||||
case 1:
|
||||
// Ici, aucune idée de la bonne version
|
||||
// Aussi un coup de poker avec Benjelloun.
|
||||
// (lecture du fichier 2x vs pas de template+2conteneurs en paramètres)
|
||||
|
||||
// Avec la première fonction lecture
|
||||
// lecture_fichier(belges, etrangeres, "Biere2.txt");
|
||||
|
||||
// Avec la seconde utilisant des templates et un filtre
|
||||
lecture_fichier_filtre<list<Biere>, Biere>(belges, "Belge", "Biere2.txt");
|
||||
lecture_fichier_filtre<vector<Biere>, Biere>(etrangeres, "Etrangere", "Biere2.txt");
|
||||
|
||||
cout << "Bières Belges:" << endl;
|
||||
affichage(belges);
|
||||
cout << "Bières étrangères" << endl;
|
||||
affichage(etrangeres);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (saisie_type_biere() == "Belge") {
|
||||
ajout<list<Biere>, Biere>(belges);
|
||||
cout << "Bières Belges:" << endl;
|
||||
affichage(belges);
|
||||
}
|
||||
else {
|
||||
ajout<vector<Biere>, Biere>(etrangeres);
|
||||
cout << "Bières étrangères" << endl;
|
||||
affichage(etrangeres);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
saisie_seuil(seuil);
|
||||
|
||||
erase_seuil_alcool(belges, seuil);
|
||||
erase_seuil_alcool(etrangeres, seuil);
|
||||
|
||||
cout << "Bières Belges:" << endl;
|
||||
affichage(belges);
|
||||
cout << "Bières étrangères" << endl;
|
||||
affichage(etrangeres);
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
cout << "Les bières belges la plus chères sont" << endl;
|
||||
plus_cher(belges);
|
||||
cout << "Les bières étrangères la plus chères sont" << endl;
|
||||
plus_cher(etrangeres);
|
||||
|
||||
break;
|
||||
default:
|
||||
return 0; // sortie
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Biere::saisie(ifstream& s) {
|
||||
string tmp;
|
||||
getline(s, nom, ';');
|
||||
getline(s, type, ';');
|
||||
|
||||
|
||||
getline(s, tmp, ';');
|
||||
|
||||
// POUR UNE RAISON QUE J'IGNORE complétement, sur VisualStudio 2022
|
||||
// Avec windows en FRANCAIS, le stof lis les nombre avec des VIRGULES et pas des points
|
||||
// Il est nécessaire de retirer ceci en fonction de la plateforme ou du compilateur
|
||||
// Voir même de la langue de Windows (on pourra le faire mais je le fais pas)
|
||||
replace(tmp.begin(), tmp.end(), '.', ',');
|
||||
|
||||
|
||||
deg_alcool = stof(tmp); // fonction stof: String TO Float
|
||||
|
||||
getline(s, tmp, ';');
|
||||
|
||||
// Pareil ici :/
|
||||
replace(tmp.begin(), tmp.end(), '.', ',');
|
||||
|
||||
prix = stof(tmp);
|
||||
|
||||
getline(s, region, '\n');
|
||||
}
|
||||
|
||||
void Biere::affichage() {
|
||||
cout << nom << "; " << type << "; " << deg_alcool << "; " << prix<<"; "<<region<<endl;
|
||||
}
|
||||
|
||||
void Biere::saisie() {
|
||||
cout << "Nom de la bière : ";
|
||||
getline(cin, nom);
|
||||
cout << "Un type : ";
|
||||
getline(cin, type);
|
||||
cout << "Un degré d'alcool : ";
|
||||
cin >> deg_alcool;
|
||||
cout << "Prix : ";
|
||||
cin >> prix; cin.ignore();
|
||||
cout << "Région/Pays : ";
|
||||
getline(cin, region);
|
||||
}
|
||||
Reference in New Issue
Block a user