Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercices] Venez vous entraîner !

(v2)

30 mai 2015 à 12:29:59

C'est vrai qu'une fonction doit être simple, et ne doit faire qu'une action simple. Si ton but est de te faciliter la vie, tu vas voir que la POO est faite pour toi ;)
  • Partager sur Facebook
  • Partager sur Twitter
31 mai 2015 à 16:09:40 - Message modéré pour le motif suivant : Le flood est strictement interdit


31 mai 2015 à 16:12:18 - Message modéré pour le motif suivant : Le flood est strictement interdit


13 juin 2015 à 21:25:01

Bonsoir la famille vous allez bien?je suis nouveau sur ce forum et je le trouve super cool.J'ais un petit exercice la :Réalisez une classe de type compte en banque, en y intégrant deux méthodes, l’une déposant de l’argent,
l’autre en retirant, et dont vous vous assurerez que l’attribut solde ne puisse jamais être négatif.Dans la même classe écrivez une méthode d’accès au solde, qui retourne ce
dernier comme un entier, alors qu’il est stocké comme un réel.
  • Partager sur Facebook
  • Partager sur Twitter
Big-ROG
22 juin 2015 à 18:34:46

C'est beaucoup trop simple

  • Partager sur Facebook
  • Partager sur Twitter
25 juin 2015 à 10:12:03

ha oui tu trouves? moi par contre je le ferrais plus facilement en un bloc mais comme le livre ou j'ai tiré cet exercice aborde la notion de l'orientée objet donc j'ai encore un peu de mal avec les classes...
  • Partager sur Facebook
  • Partager sur Twitter
Big-ROG
20 juillet 2015 à 1:57:54

Bonjour a tous voila mon premier message ici et c'etait pour que vous jugiez le resultat de l'exercice sur les fonctions a deux arguments, voila je l'ai entierement fait moi meme, fait et refait et refait encore pour etre honnete mais j'ysuis arrivé ! alors voila :

#include <iostream>

using namespace std;



char signe('a');
void dessineRectangle(int l, int h)
{
    for(int ligne(0); ligne < h; ligne++)
    {
        for(int colonne(0); colonne < l; colonne++)
        {
            cout << signe ;
        }
        cout << endl;
    } 
}


int main()
{
	cout<<" choisissez votre signe afin de dessiner le rectangle"<< endl;
	cin >> signe ;
 
    int largeur, hauteur;

    do
    {
        cout << "Largeur du rectangle ?" ;
        cin >> largeur;
		cout <<"Hauteur du rectangle?";
		cin >> hauteur;
    if (( largeur <0) || (hauteur <0))
 { cout<<"Erreure chiffre"<< endl; 
 }

	
	} while ((largeur <0)|| (hauteur < 0));
		
		
    dessineRectangle(largeur, hauteur);
	system("pause");
    return 0;
}

le "cahier des charges" demandait a la base simplement : de rajouter  un message d'erreur si la hauteur ou la largeur est négative et un argument pour le symbole à utiliser dans le dessin. Mais je me suis dis qu'un simple message d'erreur etait un peu "trop simpliste" et j'ai donc fait la boucle qui ne valideralafonction quesi les deux chiffreentier sont positif,c'est plus complet je trouve, alors voila dites moiceque vous en pensez :D

  • Partager sur Facebook
  • Partager sur Twitter
5 août 2015 à 23:49:47

TheSasukz a écrit:

Solution pour l'interpréteur BF...

Bonjous,

Bon, c'est un exercice de plus d'un an, mais je suis nouveau ici et je fait les exercices passés,

Pour celui la j'ai repris la solution de TheSasukz je me suis permis d'ajouter les fonctions de boucle, pour m'entrainer a utiliser les streams et les listes. Je comprend pas le problème du dernier caractère qui est traité deux fois,

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <list>
using namespace std; // Ergonomie "maximum"
int main(){
    // Déclaration et initialisation des variables "principales"
    char v[30000], l(' ');
    int i = 29999;
    string fName(" ");
    list<streampos> positions; // liste des pointeurs d'entrée de boucle
    bool pass = false;         // 2 variables pour passer les boucles avec 0 en entrée
    int passCount = 0;

    while (i >= 0) v[i--] = 0;

    i = 0; // Préparation du "pseudo-pointeur"

    cout << "EXERCICE CPP - INTERPRETEUR BRAINF." << endl;
    cout << "Entrez le nom du fichier TXT source (sans extension)" << endl;
    cin >> fName;
    cout << endl << "> ";
    string ext(fName+".txt"); // Rapide concaténation
    ifstream iStr(ext.c_str()); // On ouvre le flux de fichier
    if (iStr) {
        while (iStr.good()) { // Tant que le fichier est "bon" à la lecture, on lit
            iStr.get(l);
            if (pass) {                           // Mode pass, si une boucle a 0 en entrée,
                switch (l) {                      // on ignorre tout sauf les [ et les ]

                    case '[': passCount++; break; // On compte les boucles imbriquées dans la boucle a ignorer

                    case ']':
                        if (passCount > 0)
                            passCount--;          // pour chaque boucle imbriquée, on ignore un point de sortie
                        else
                            pass = false;         // et on repasse en mode normal lorsqu'on a trouvé la sortie
                        break;
                }
            } else {
                switch (l) {
                    // Instructions de déplacement du pseudo-pointeur
                    case '<': if (i != 0) { i--; } break;
                    case '>': if (i != 29999) { i++; } break;

                    // Instructions de dé/incrémentation
                    case '+': v[i]++; break;
                    case '-': if (v[i] > 0) v[i]--;  break;

                    // Instructions d'entrée/sortie de valeurs
                    case '.': cout << v[i]; break;
                    case ',': cin >> v[i]; break;

                    // Boucles
                    case '[':
                        if (v[i] > 0)                          // si on entre dans une boucle avec un compteur
                            positions.push_back(iStr.tellg()); // on ajoute son adresse dans la liste
                        else                                   // si le compteur est a 0 à l'entréee,
                            pass = true;                       // on passe en mode de recherche de la sortie de boucle.
                        break;

                    case ']':
                        if (positions.empty()) // si on a un point de sortie mais qu'on a plus de point d'entrée...
                            cout << "erreur ] sans [";
                        else{
                            if (v[i] ==0)  // si le compteur est a 0 on se debarrase du point d'entrée
                                positions.pop_back();
                            else{ // si le compteur est différent de 0, on recupère le point d'entrée dans la liste
                                list<streampos>::reverse_iterator posIter = positions.rbegin();
                                iStr.seekg(*posIter);
                            }
                        }
                        break;
                }
            }
            l = ' ';
        }
    } else { // Si le fichier est illisible/introuvable
        cout << endl << "ERREUR : Flux de fichier inutilisable" << endl;
    }
    cout << endl;
    system("PAUSE");
    return 0;
}

J'ai ajouté l=' ' a la fin de la boucle pour éviter que le dernier caractère soit traité deux fois mais ce n'est pas satisfaisant.

Je suis ouvert aux suggestions.

  • Partager sur Facebook
  • Partager sur Twitter
...
6 août 2015 à 0:17:34

Je pense avoir trouvé, il faut que la fonction get(l) échoue pour que le test good soit faux, donc on fait une boucle de trop.

J'ai essayé de remplacer good par !eof mais ca ne marche pas non plus.

J'ai déplacé la fonction get a la fin de la boucle, la première boucle ne fait rien vu qu'on initialise a ' ' et l'état du fichier est correct au moment de le tester.

  • Partager sur Facebook
  • Partager sur Twitter
...
6 août 2015 à 8:48:05

@CQui : quand tu as besoin d'informations par rapport à ta réalisation d'un exercice particulier, poste plutôt un nouveau sujet. Accessoirement cette solution a des choses à revoir :

  • utilisation de tableau à la C,
  • pré-déclarations de variables,
  • pas de découpage en fonctions,
  • utilisation d'une liste plutôt qu'un vector,
  • ...
  • Partager sur Facebook
  • Partager sur Twitter
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
9 août 2015 à 23:38:48

Bonjour tout le monde, voici un petit exo que je trouve vraiment sympa, bien qu'assez complexe. Le but est de créer une machine à résoudre les énigmes de logique telle que la suivante :

Une bijouterie a été cambriolée. L'inspecteur a trois suspects: André, Bill et Charlie.

Voici ce qu'il a déduit de l'interrogatoire :

-L'un des trois au moins est coupable.

-Si André est coupable, au moins l'un des deux autres est innocent.

-Si Bill est innocent, Charlie l'est aussi.

-Il est impossible que André soit seul innocent.

-Si Charlie est innocent, Bill l'est aussi.

Qui est le coupable ?

Voici donc l'exercice Résolveur d'énigme, dans la catégorie Jeux.

Une des difficultés de cet exercice étant la manipulation d'assertions logiques, et parce qu'il est un peu long, il sera un peu guidé, mais rien ne vous empêche de trouver votre propre solution. Je suis également disponible pour répondre (même par MP si vous le souhaitez) à vos questions :)

Enfin, vous aurez probablement besoin d'implémenter d'autres fonctions que les principales qui vous sont suggérées. L'usage d'une classe n'apporte pas grand chose à cet exercice, vous êtes libres de tout encapsuler ou non ;)

Par ailleurs, cet exercice vous amènera à manipuler les Piles/Stacks et les exceptions :)

Description :

Pour transcrire les hypothèses de l'énigme en assertions logiques (c'est a dire en phrases utilisant des connecteurs logiques), on utilisera la notation polonaise inversée ou notation post-fixée (https://fr.wikipedia.org/wiki/Notation_polonaise_inverse). Pour bien comprendre, voici des exemples de transcription en notation post-fixée :

(A ou B) et C    donne:   ( A B ou C et)

(A => B) et (C => D)    donne:    (A B => C D =>  et)

(Je peux rajouter des exemples si vous voulez)

La notation post-fixée allant naturellement de pair avec les piles, on écrira les propositions sous la forme

enum Element

            {
                False,
                True,
                Et,
                Ou,
                Non,
                Implique,
                Equivaut,
                A,
                B,
                C
            };



using Proposition = std::stack<Element>;

où l'énumérateur Elementcontient tous les éléments logiques qui apparaîtront dans nos propositions(A, B et C feront offices de variables).

Étape 1 :

Écrire une fonction var_libres prenant en paramètre une Proposition prop et renvoyant une Proposition contenant les variables de prop (c'est à dire les éléments différents de False/True/Et/Ou/Non/Implique/Equivaut).



Étape 2 :

On appelle environnement un ensemble de booléens associé aux variables. On rajoute donc la ligne :

using Environnement = std::vector<bool>;

Par exemple, si les variables sont [A, B, C] et l'environnement associé est [true, false, false], alors A vaut true, B vaut false et C vaut false.

Afin de pouvoir parcourir tous les environnement pouvant être associés aux variables, il faut maintenant définir une fonction incr prenant en paramètre un environnement et renvoyant l'environnement suivant dans l'ordre lexicographique.

Par exemple, voici une succession d'incrémentations pour un environnement à trois variables :

false false false

false false true

false true false

false true true

true false false

(je rappelle que vous avez le droit de me demander des explications plus précises, ce n'est pas forcément trivial :-°)

Si l'environnement passé en paramètre est maximal (true true true), incr doit lancer une exception IncrMax.

Il faut également définir une fonction evaluequi prend en paramètre une Proposition et un Environnement, et doit renvoyer la valeur de vérité (true ou false) de la proposition, les variables étant évaluées grâce à l'Environnement.

Étape 3 :

On y est presque :D . Maintenant, il faut coder une fonction satisfiable qui prend une Proposition en paramètre, et qui teste tous les environnements possibles jusqu'à en trouver un tel que la Proposition soit vraie pour cet environnement. Cet Environnement est alors la valeur renvoyée.

S'il n'y en a aucun, la fonction doit lancer une exception Insatisfiable.

On définit enfin une tautologie comme une expression qui est toujours vraie, quelques soient les valeurs de ses variables (exemple : A ou (non A)), c'est à dire que son contraire est insatisfiable. La dernière fonction (dont on pourrait en fait se passer pour résoudre l'énigme) à écrire est alors la fonction tautologie, prenant une Proposition en paramètre, et vérifiant si c'est une tautologie. Si c'est le cas, elle lance une exception Tautologie. Sinon, elle renvoie un Environnement contre-exemple, c'est a dire qui rend la Proposition fausse.

Ultime Étape :

Maintenant, il ne reste plus qu'à écrire l’énigme sous forme de Proposition, et à utiliser la fonction tautologie pour déterminer le(s) coupable(s). Pour vérifier vos résultats, vous pouvez facilement résoudre l'énigme de tête :)

Vous pouvez, si vous le préférez, commencer par faire des tests avec les propositions suivantes :

- (P et (non P)) est insatisfiable.

- (P ou (non P)) est une tautologie.

- (P => Q) => ((non Q) => (non P)) est une tautologie (vous venez de démontrer le principe de contraposition).

-
Edité par UnCodeurCommeUnAutre 10 août 2015 à 0:22:14

  • Partager sur Facebook
  • Partager sur Twitter
Il y a toujours un moyen de le faire. Il y a toujours un meilleur moyen de le faire.
9 août 2015 à 23:40:58

Par contre petite question à Germino et Equinoxe : dois-je vous envoyer la correction, ou la poster moi même dans quelques jours ?
  • Partager sur Facebook
  • Partager sur Twitter
Il y a toujours un moyen de le faire. Il y a toujours un meilleur moyen de le faire.
11 août 2015 à 3:31:03

super ca + 1,je vais essayer ca housse sony xperia z3  housse samsung galaxy tab 4

-
Edité par riversemin 13 août 2015 à 6:15:10

  • Partager sur Facebook
  • Partager sur Twitter
11 août 2015 à 11:52:08

@UnCodeurCommeUnAutre : poste un sujet sur le forum, selon le volume de code, soit un dépôt git, soit le code directement dans la page (du coupici ce sera plus souvent le dépôt git), et les gens le commenteront ;) .

  • Partager sur Facebook
  • Partager sur Twitter
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
28 octobre 2015 à 22:13:26

Soient deux listes chaînées d’entiers écrire trois fonctions permettant de vérifier si 
elles sont égales, similaires ou comparables.
- Deux listes sont égales si elles contiennent les mêmes éléments aux mêmes 
positions.
- Deux listes sont similaires si elles contiennent les mêmes éléments mais pas 
forcément aux mêmes positions. Exemple : [9,6,7,6,3,6,1,9] et [1,3,6,6,6,7,9,9] 
sont similaires alors que [9,6,7,6,3,6,1,9] et [9,9,7,6,3,6,1,9] ne le sont pas.
- Deux listes sont comparables si l'ensemble des valeurs qu'elles contiennent 
est le même. Exemple, les listes [1,3,6,7,9] et [9,6,7,6,3,6,1,9] sont 
comparables.
puis je avoir une solution pr la fonction similaire
  • Partager sur Facebook
  • Partager sur Twitter
29 octobre 2015 à 8:40:11

2- sort(vector1) == sort(vector2)

3- set(v1) == set(v2)

La syntaxe n'est évidemment pas la bonne -- quoique, en C++17/avec les ranges d'Eric Niebler, je ne serai pas si sûr.

  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
6 novembre 2015 à 18:59:09

Bonjour :lol:

Voici une solution pour l'exercice P'tit Langage.

J'utilise les propriétés c++11 suivantes :

  • fonction std::stoi de <string>
  • la classe d'erreurs std::invalid_argument (pour récupérer les exceptions dues à stoi, si ce n'est pas un nombre)

Il n'y a pas beaucoup de commentaires, je pourrais en rajouter si vous le voulez. J'ai implémenté toutes les fonctions proposées, en changeant quelques trucs :

  • le define n'est utilisé que pour définir les fonctions, pour les variables on utilise set (comme pour les modifier)
  • j'ai remplacé set! par set
  • l'opérateur "," renvoie un nombre qui identifie le tableau dans un autre tableau
  • les noms de variables/de fonctions doivent suivre la regex suivante : [a-zA-Z]*
  • l'opérateur de séquence (begin expr1 expr2 ...) est remplacé par (expr1 expr2 ...)

Je suis ouverts aux commentaires pour améliorer mon code ;)

Il est un peu long, donc si vous avez un site pour le mettre à votre disposition ce serait volontiers, je pourrais le retirer de ce message car là il encombre un peu... :euh:

Merci d'avance !

main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include "bloc.h"

using namespace std;

// Fonction pour afficher l'aide de l'exécutable
void help(char* s){
	cout << "Interpréteur P'tit Langage 0.1" << endl;
	cout << "Syntaxe : " << s << " file.ptl [options]" << endl;
	cout << "Codes de retour :" << endl;
	cout << "\t0 OK (tout s'est bien passé)" << endl;
	cout << "\t1 ARGUMENTS INVALIDES (arguments trop nombreux)" << endl;
	cout << "\t2 ERREUR FICHIERS (problème lors de l'ouverture ou de la lecture du fichier)" << endl;
	cout << "\t3 ERREUR PROGRAMME (erreur dans le programme)" << endl;
}

int main(int argc, char* argv[]){
	// En fonction du nombre d'argument
	switch(argc){
		case 1: // -> Aucun : on affiche l'aide, et on arrête le programme.
			help(argv[0]);
			return 0;
		case 2: // -> Un : on exécute le contenu du fichier spécifié.
			break;
		default: // -> Autre : on affiche l'aide et on arrête le programme (code d'erreur 1).
			cerr << "Vous avez saisi un nombre invalide d'arguments." << endl;
			help(argv[0]);
			return 1;
	}

	// Ouverture du fichier
	ifstream file(argv[1]);
	string text;
	string line;
	if(file){ // -> Ça marche, on lit le fichier.
		while(getline(file, line)){
			text += line + ' ';
		}
	} else { // -> Il y a eu une erreur, on l'affiche et on arrête le programme (code d'erreur 2).
		cerr << "Ouverture du fichier " << argv[1] << " impossible." << endl;
		return 2;
	}

	// ANALYSE SÉMANTIQUE DE LA PREMIÈRE COMMANDE
	Bloc prgm(text);

	// S'il y a eu une erreur, on quitte le programme.
	if(variables["ERROR"] < 0) return 3;

	// EXÉCUTION DE LA PREMIÈRE COMMANDE
	int n = prgm.exec();
	if(variables["ERROR"] < 0) return 3; // S'il y a eu une erreur, on quitte le programme.
	if(show(prgm.getType())) cout << n << endl;

	// ANALYSE SÉMANTIQUE ET EXÉCUTION DES AUTRES COMMANDES
	while(prgm.getEnd() < text.size()-1){
		prgm = Bloc(text, prgm.getEnd() + 1);
		if(variables["ERROR"] < 0) return 3; // S'il y a eu une erreur, on quitte le programme.
		n = prgm.exec();
		if(variables["ERROR"] < 0) return 3; // S'il y a eu une erreur, on quitte le programme.
		if(show(prgm.getType())) cout << n << endl;
	}
	return 0;
}

bloc.h

#ifndef BLOC_H
#define BLOC_H

#include <string>
#include <vector>
#include <iostream>
#include <map>

// Types de bloc
enum BlocType {		//								EXPLICATION												SYNTAXE/NOM DE LA COMMANDE
	NONE,			// Bloc vide présent s'il y a des caractères blancs à la fin du programme
	NOMBRE,			// Nombre en dur (pas une expression)										Ex : 256
	VARIABLE,		// Nom de variable															Ex : var
	ADDITION, 		// |																		+
	SOUSTRACTION,	// | ---\  Opérations pour lesquelles 										-
	MULTIPLICATION,	// | ---/ il faut calculer le résultat										*
	DIVISION,		// |																		/
	SET,			// Assignation d'une valeur à une variable (il n'y a pas de déclaration)	set
	IF,				// Condition : (if condition faisca sinonfaisca)							if
	AND,			// ET logique dans une condition											and
	OR,				// OU logique dans une condition											or
	NOT,			// NON logique dans une condition											not ou !
	LT,				// Plus petit que															<
	GT,				// Plus grand que															>
	EQ,				// Égal																		=
	LE,				// Plus petit ou égal														<=
	GE,				// Plus grand ou égal														>=
	SEQUENCE,		// Opérateur de séquence - Faire précéder nombres et variables d'un espace	(expr1 expr2 expr3 ...)
	WHILE,			// Boucle tant que															while
	LET,			// Déclaration de variables locales											let
	DEFINE,			// Définition de fonction													(define nomdelafonction param1 param2 ... expr)
	FUNCTION,		// Exécution de fonction													(nomdelafonction param1 param2 ...)
	QUIET,			// Opérateur de séquence sans la sortie standard							(quiet expr1 expr2 ...)
	NUPLET,			// Opérateur de création de couple 											,
	NTH				// Opérateur d'accès à un des champs d'un couple							(nth nieme liste)
};

// Fonction qui définit s'il faut montrer un type de bloc ou non
bool show(BlocType t){
	switch(t){
		case NOMBRE:			// Renvoie la valeur numérique
		case ADDITION:			// Renvoie le résultat de l'opération
		case SOUSTRACTION:		// Renvoie le résultat de l'opération
		case MULTIPLICATION:	// Renvoie le résultat de l'opération
		case DIVISION:			// Renvoie le résultat de l'opération
		case VARIABLE:
		case LET:
		case FUNCTION:
		case NTH:
			return true;
		default:				// Dans la plupart des cas, on n'affiche pas le résultat, car il n'a aucune signification
			return false;
	}
}


// Classe représentant un bloc de commandes, comme (+ 3 2) ou (+ (let ((x 3) (y 2)) (* x y)) (/ 9 4))
class Bloc {
public:
	Bloc();
	Bloc(std::string s, int b=0); // Constructeur. S = string à analyser; B = charactère de S à partir duquel commencer.
	int exec(std::map<std::string, int> localVars=std::map<std::string, int>());                   // Exécution du bloc de commandes.
	int getEnd(){ return end; };		// Accesseur.
	BlocType getType(){ return type; };	// Accesseur.

private:
	std::vector<Bloc> blocs;				// Sous bloc, paramètres de la commande
	int beginning;							// Caractère de “text” à partir duquel commence le bloc
	int end;								// Caractère de “text” où se finit le bloc
	int number;								// Nombre représenté par le bloc si c'en est un
	std::string text;						// Programme
	std::string name;						// Nom si c'est une variable
	BlocType type;							// Type du bloc
};

std::map<std::string, int> variables;
std::map<std::string, std::pair<std::vector<std::string>, Bloc> > fonctions; // -> std::map<nom_de_la_fonction, std::pair<noms_des_parametres, corps> >
std::vector<std::vector<int> > nuplets;

Bloc::Bloc(): blocs(), beginning(0), end(0), text(""), type(NONE){ // } // CONSTRUCTEUR / ANALYSE SÉMANTIQUE Bloc::Bloc(std::string s, int b): blocs(), beginning(b), text(s){ bool firstp = true; std::string command; for(int i=beginning; i<text.size(); i++){ if(text[i] == ' ' || text[i] == '\n' || text[i] == '\n') continue; if(text[i] == ')'){ if(firstp){ std::cerr << "Parenthèse ouvrante manquante." << std::endl; variables["ERROR"] = -1; } end = i; break; } if(firstp){ firstp = false; // On commence un bloc "commande" if(text[i] == '('){ i++; while(text[i] != ' ' && text[i] != '\n' && text[i] != '\t' && text[i] != '('){ command += text[i]; i++; } if(command == "+") type = ADDITION; else if(command == "-") type = SOUSTRACTION; else if(command == "*") type = MULTIPLICATION; else if(command == "/") type = DIVISION; else if(command == "if") type = IF; else if(command == "not" || command == "!") type = NOT; else if(command == "and") type = AND; else if(command == "or") type = OR; else if(command == "<") type = LT; else if(command == ">") type = GT; else if(command == "=") type = EQ; else if(command == "<=") type = LE; else if(command == ">=") type = GE; else if(command == "define") type = DEFINE; else if(command == "quiet") type = QUIET; else if(command == ",") type = NUPLET; else if(command == "nth") type = NTH; else if(command == "let"){ type = LET; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; if(text[i] != '('){ std::cerr << "LET : parenthèse ouvrante manquante; let doit être suivi de la liste des variables locales sous la forme : (let ((var1 val1) (var2 val2) ...) expr)" << std::endl; variables["ERROR"] = -1; return; } i++; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; while(text[i] != ')'){ if(text[i] != '('){ std::cerr << "LET : parenthèse ouvrante manquante; let doit être suivi de la liste des variables locales sous la forme : (let ((var1 val1) (var2 val2) ...) expr)" << std::endl; variables["ERROR"] = -1; return; } i++; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; Bloc b(text, i); blocs.push_back(b); // Un bloc avec le nom de la variable i = b.end + 1; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; b = Bloc(text, i); blocs.push_back(b); // Un bloc avec la valeur à attribuer à la variable i = b.end + 1; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; if(text[i] != ')'){ std::cerr << "LET : parenthèse fermante manquante après la déclaration de la variable locale “" << command << "”." << std::endl; variables["ERROR"] = -1; return; } i++; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; } i++; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; Bloc b(text, i); blocs.push_back(b); i = b.end; i++; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; if(text[i] != ')'){ std::cerr << "LET : parenthèse fermante manquante après la fin de la commande." << std::endl; variables["ERROR"] = -1; return; } if(blocs.size() % 2 != 1){ std::cerr << "LET : nombre incorrect de paramètres." << std::endl; variables["ERROR"] = -1; return; } end = i; break; } else if(command == ""){ type = SEQUENCE; i--; } else if(command == "while") type = WHILE; else if(command == "set"){ type = SET; command = ""; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; // On lit le nom de la variable while(text[i] != ' ' && text[i] != '\n' && text[i] != '\t'){ if((text[i] < 'a' || text[i] > 'z') && (text[i] < 'A' || text[i] > 'Z')){ // Les noms de variable ne peuvent contenir que des lettres std::cerr << "SET : un nom de variable ne doit contenir que des lettres (minuscules ou majuscules)." << std::endl; variables["ERROR"] = -1; return; } command += text[i]; i++; } name = command; // On enregistre le nom de la variable. Bloc b(text, i); // On analyse le bloc suivant, contenant la valeur à donner à la variable. blocs.push_back(b); i = b.end+1; while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++; if(text[i] != ')'){ std::cerr << "SET : trop d'arguments, la syntaxe est (set variable valeur)" << std::endl; variables["ERROR"] = -1; } end = i; break; } else { type = FUNCTION; name = command; } } else { // C'est un nombre ou une variable type = NOMBRE; // On lit while(text[i] != ' ' && text[i] != '\n' && text[i] != '\t' && text[i] != ')'){ command += text[i]; i++; } // On essaye de convertir en nombre try { number = std::stoi(command); } catch(std::invalid_argument e){ // Si ça marche pas -> c'est une variable, on prend la valeur de la variable. type = VARIABLE; for(int i = 0; i<command.size(); i++){ if((command[i] < 'a' || command[i] > 'z') && (command[i] < 'A' || command[i] > 'Z')){ // Vérification que la variable ne contient que des caracères de l'alphabet std::cerr << command << " : un nom de variable ne doit contenir que des lettres (minuscules ou majuscules)." << std::endl; number = -1; variables["ERROR"] = -1; return; } } name = command; } end = i-1; break; } } else { Bloc b(text, i); blocs.push_back(b); i = b.end; } } if(firstp){ type = NONE; end = text.size()-1; } else if(end == text.size()-1 && text[end] != ')'){ std::cerr << "Parenthèse fermante manquante." << std::endl; variables["ERROR"] = -1; } if(type == IF){ if(blocs.size() < 2){ std::cerr << "IF : Argument(s) manquant(s). Syntaxe : (if condition faisci [sinonfaisca])" << std::endl; variables["ERROR"] = -1; } else if(blocs.size() > 3){ std::cerr << "IF : Trop d'arguments. Syntaxe : (if condition faisci [sinonfaisca])" << std::endl; variables["ERROR"] = -1; } } if(type == NOT){ if(blocs.size() > 1){ std::cerr << "NOT : Trop d'arguments. Syntaxe : (not condition) ou (! condition)" << std::endl; variables["ERROR"] = -1; } else if(blocs.size() == 0){ std::cerr << "NOT : Argument manquant. Syntaxe : (not condition) ou (! condition)" << std::endl; variables["ERROR"] = -1; } } if(type == OR && blocs.size() < 2){ std::cerr << "OR : Argument(s) manquant(s). Syntaxe : (or condition1 condition2 [condition3 ...])" << std::endl; variables["ERROR"] = -1; } if(type == AND && blocs.size() < 2){ std::cerr << "AND : Argument(s) manquant(s). Syntaxe : (and condition1 condition2 [condition3 ...])" << std::endl; variables["ERROR"] = -1; } if(type == LT || type == GT || type == EQ || type == LE || type == GE){ if(blocs.size() < 2){ std::cerr << "COMPARAISON : Argument(s) manquant(s). Syntaxe : (comparaison expr1 expr2)" << std::endl; variables["ERROR"] = -1; } else if(blocs.size() > 2){ std::cerr << "COMPARAISON : Trop d'arguments. Syntaxe : (comparaison expr1 expr2)" << std::endl; variables["ERROR"] = -1; } } if(type == WHILE){ if(blocs.size() < 2){ std::cerr << "WHILE : Argument(s) manquant(s). Syntaxe : (while condition expr)" << std::endl; variables["ERROR"] = -1; } else if(blocs.size() > 2){ std::cerr << "WHILE : Trop d'arguments. Syntaxe : (while condition expr)" << std::endl; variables["ERROR"] = -1; } } if(type == DEFINE){ if(blocs.size() < 2){ std::cerr << "DEFINE : Pas assez d'arguments. Syntaxe : (define nomdelafonction [param1 [param2 [...]]] expr)" << std::endl; variables["ERROR"] = -1; } for(int i=0; i<blocs.size()-1; i++){ if(blocs[i].type != VARIABLE){ std::cerr << "DEFINE : tous les arguments sauf le dernier doivent être des noms type variable. Erreur pour l'argument : " << i+1 << "." << std::endl; variables["ERROR"] = -1; return; } } } } // EXÉCUTION int Bloc::exec(std::map<std::string, int> localVars){ int n; bool m; switch(type){ case NOMBRE: return number; case VARIABLE: if(localVars.find(name) != localVars.end()) return localVars[name]; else if(variables.find(name) != variables.end()) return variables[name]; else { variables["ERROR"] = -1; std::cerr << "Variable " << name << " indéfinie." << std::endl; break; } case ADDITION: n = 0; for(int i=0; i<blocs.size(); i++){ n += blocs[i].exec(localVars); } return n; case SOUSTRACTION: n = blocs[0].exec(localVars); for(int i=1; i<blocs.size(); i++){ n -= blocs[i].exec(localVars); } return n; case MULTIPLICATION: n = 1; for(int i=0; i<blocs.size(); i++){ n *= blocs[i].exec(localVars); } return n; case DIVISION: n = blocs[0].exec(localVars); for(int i=1; i<blocs.size(); i++){ n /= blocs[i].exec(localVars); } return n; case SET: n = blocs[0].exec(localVars); variables[name] = n; return n; // On renvoie la nouvelle valeur de la variable. case IF: if(blocs[0].exec(localVars) != 0){ n = blocs[1].exec(localVars); if(show(blocs[1].type)) std::cout << n << std::endl; } else if(blocs.size() > 2){ n = blocs[2].exec(localVars); if(show(blocs[2].type)) std::cout << n << std::endl; } break; case NOT: return blocs[0].exec(localVars) == 0; case OR: m = blocs[0].exec(localVars); for(int i=1; i<blocs.size(); i++){ m = (m || (blocs[i].exec(localVars) != 0)); } return m; case AND: m = blocs[0].exec(localVars); for(int i=1; i<blocs.size(); i++){ m = (m && (blocs[i].exec(localVars) != 0)); } return m; case LT: return blocs[0].exec(localVars) < blocs[1].exec(localVars); case GT: return blocs[0].exec(localVars) > blocs[1].exec(localVars); case EQ: return blocs[0].exec(localVars) == blocs[1].exec(localVars); case LE: return blocs[0].exec(localVars) <= blocs[1].exec(localVars); case GE: return blocs[0].exec(localVars) >= blocs[1].exec(localVars); case SEQUENCE: for(int i=0; i<blocs.size(); i++){ n = blocs[i].exec(localVars); if(show(blocs[i].type)) std::cout << n << std::endl; } return n; case WHILE: while(blocs[0].exec(localVars) != 0){ n = blocs[1].exec(localVars); if(show(blocs[1].type)) std::cout << n << std::endl; } break; case LET: for(int i=0; i<blocs.size()-1; i+=2){ localVars[blocs[i].name] = blocs[i+1].exec(localVars); } return blocs[blocs.size()-1].exec(localVars); case DEFINE: name = blocs[0].name; if(fonctions.find(name) != fonctions.end()){ std::cerr << "DEFINE : Redéfinition de la fonction : " << name << "." << std::endl; variables["ERROR"] = -1; break; } fonctions[name] = std::pair<std::vector<std::string>, Bloc>(std::vector<std::string>(), blocs[blocs.size()-1]); for(int i=1; i<blocs.size()-1; i++){ fonctions[name].first.push_back(blocs[i].name); } break; case FUNCTION: if(fonctions.find(name) != fonctions.end()){ if(blocs.size() != fonctions[name].first.size()){ std::cerr << "Nombre de paramètres invalide pour la fonction " << name << " : " << fonctions[name].first.size() << " paramètres attendus, " << blocs.size() << "reçus." << std::endl; variables["ERROR"] = -1; return -1; } for(int i=0; i<blocs.size(); i++){ localVars[fonctions[name].first[i]] = blocs[i].exec(localVars); } return fonctions[name].second.exec(localVars); } else { std::cerr << "Fonction non définie : " << name << "." << std::endl; variables["ERROR"] = -1; return -1; } case QUIET: for(int i=0; i<blocs.size()-1; i++){ blocs[i].exec(localVars); } return blocs[blocs.size()-1].exec(localVars); case NUPLET: n = nuplets.size(); nuplets.push_back(std::vector<int>()); for(int i=0; i<blocs.size(); i++){ nuplets[n].push_back(blocs[i].exec(localVars)); } return n; // On renvoie l'endroit où on a enregistré le couple dans le tableau nuplets. case NTH: return nuplets[blocs[1].exec(localVars)][blocs[0].exec(localVars)]; } return -1; } #endif



-
Edité par Moi moi moi 6 novembre 2015 à 19:09:07

  • Partager sur Facebook
  • Partager sur Twitter
6 novembre 2015 à 19:24:43

Lu'!

Découpe ton code, des fonctions de 150 lignes, c'est (au moins) 10 fois trop long, et là on en a une qui fait 220 lignes. Sans parler de l'inextensibilité complète du bordel que ça produit. Et ta classe bloc (nom très mal choisi) a beaucoup trop de responsabilités différentes : 1 classe = 1 unique responsabilité (SRP).

-
Edité par Ksass`Peuk 6 novembre 2015 à 19:26:21

  • Partager sur Facebook
  • Partager sur Twitter
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
6 novembre 2015 à 19:28:00

Ok je vais essayer ça.

Je modifierais le code de départ après :D

Pour la classe bloc, elle n'a pour moi qu'une seule responsabilité : elle représente une instruction et permet de l'exécuter.

  • Partager sur Facebook
  • Partager sur Twitter
6 novembre 2015 à 19:34:47

Moi moi moi a écrit:

Pour la classe bloc, elle n'a pour moi qu'une seule responsabilité : elle représente une instruction et permet de l'exécuter.

Quedal.

Elle reçoit un programme en entrée et fait :

  • l'analyse syntaxique,
  • l'analyse sémantique,
  • l'exécution.

Ce qu'on veut c'est :

  • générer la listes des lexemes à partir du texte (minimum une classe, en vrai beaucoup plus parce qu'on doit qualifier les lexemes),
  • générer l'AST à partir des lexemes (une classe de génération + un type par possibilité de noeud d'AST), ce que tu appelles "BlocType", ça justifie bien chacun une classe quasiment,
  • faire un visiteur qui à partir d'un AST correct produit le résultat (encore une classe).

-
Edité par Ksass`Peuk 6 novembre 2015 à 19:41:50

  • Partager sur Facebook
  • Partager sur Twitter
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
6 novembre 2015 à 19:52:17

Merci pour les conseils, je vais me documenter sur ce que sont les lexemes et l'AST puis restructurer mon code :)

À bientôt !

-
Edité par Moi moi moi 6 novembre 2015 à 19:53:05

  • Partager sur Facebook
  • Partager sur Twitter
17 novembre 2015 à 23:43:36

Bonjour à tous,

je viens de finir les niveaux 1 à 4 de l'exercice Biblio++ de Germino, je souhaiterais avoir vos avis et commentaires dessus.

L'organisation des fichiers de données est la suivante :

fichier livre : 

  • chaque ligne correspond à un livre
  • l'organisation d'une ligne est la suivante :
                   N°Livre 1ou0 idEmprunteur/Titre/Auteur/Genre/DateEmprunt/DateRetour
    (Le 1 ou 0 correspond à : est ce que le livre est emprunté ou non) 

 fichier membre :

  • chaque ligne correspond à un membre
  • l'organisation d'une ligne est la suivante : 
                   ID/Nom/Prenom
L'organisation du programme est la suivante :
Il y a quatre classes :
  • Bibliothèque : qui gère le chargement des fichiers et les interactions avec l'utilisateur
  • Livre : qui gère les paramètres et l'affichage des livres
  • Membres : qui gère les paramètres et l'affichage des membres
  • Date : qui gère les dates. (je débute dans le C++, du coup j'ai préféré ne pas utiliser la classe de boost car je n'ai encore jamais utilisé cette bibliothèque)

A côté de ces classes, j'utilise des fonctions pour la saisie sécurisé issu du tutoriel de ooprog.

Le code :

Il est un peu long :(. Si certain ont un endroit ou je peux le mettre pour éviter d'encombrer le forum.

fichier main.cpp

#include <iostream>
#include "Bibliotheque.h"

using namespace std;

int main()
{
    Bibliotheque biblio("data/BaseDonneeBibliotheque.txt","data/BaseDonneeMembre.txt") ;

    biblio.bouclePrincipale() ;

    biblio.sauvegardeBiblio("data/BaseDonneeBibliotheque.txt") ;
    biblio.sauvegardeMembres("data/BaseDonneeMembre.txt") ;

    return 0;
}

Il créé la bibliothèque puis appel la fonction principal. Une fois le programme terminé, il sauvegarde les données.

 fichier Bibliotheque.h

#ifndef BIBLIOTHEQUE_H
#define BIBLIOTHEQUE_H

#include <map>
#include <string>
#include <iterator>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <limits>
#include "Livre.h"
#include "Membres.h"
#include "Date.h"
#include "inputs.h"

class Bibliotheque
{
    public:
        Bibliotheque() ;
        Bibliotheque(std::string cheminBiblio,std::string cheminMembres);
        virtual ~Bibliotheque();

        void chargementBiblio(std::string cheminBiblio) ;
        void chargementMembres(std::string cheminMembres) ;

        void sauvegardeBiblio(std::string cheminBiblio) ;
        void sauvegardeMembres(std::string cheminMembres) ;

        void ajouterLivre() ;
        void supprimerLivre() ;

        void afficherLivre(int numero = 0) ;
        void afficherBibliotheque() ;
        void afficherEmprunt() ;
        void afficherLivreMembre() ;

        int livreExiste(int numero = 0) ;

        void modifierLivre() ;

        void emprunter() ;
        void retour() ;

        void ajouterMembre() ;

        int getNombreLivre() const ;

        void bouclePrincipale() ;

    private:
        std::map<int,Livre> m_biblio ;
        std::map<int,bool> m_estEmprunte ;
        std::map<int,Membres> m_membres ;
};

#endif // BIBLIOTHEQUE_H

fichier Bibliothèque.cpp

#include "Bibliotheque.h"

Bibliotheque::Bibliotheque() {}

Bibliotheque::Bibliotheque(std::string cheminBiblio, std::string cheminMembres)
{
    chargementBiblio(cheminBiblio) ;
    chargementMembres(cheminMembres) ;
}

Bibliotheque::~Bibliotheque() {}

void Bibliotheque::chargementBiblio(std::string cheminBiblio)
{
    m_biblio.clear() ;

    std::ifstream fichier(cheminBiblio.c_str(),std::ios::in) ;
    if(fichier)
    {
        std::string ligne ;
        while(std::getline(fichier,ligne))
        {
            std::istringstream it(ligne) ;
            int numero ;
            bool emprunt ;
            it >> numero >> emprunt ;

            Livre livre(it) ;

            m_biblio.insert(std::make_pair(numero,livre)) ;
            m_estEmprunte.insert(std::make_pair(numero,emprunt)) ;
        }
        fichier.close() ;
    }
    else
        std::cerr << "Erreur à l'ouverture d'une bibliotheque" << std::endl ;
}

void Bibliotheque::chargementMembres(std::string cheminMembres)
{
    m_membres.clear() ;

    std::ifstream fichier(cheminMembres.c_str(),std::ios::in) ;
    if(fichier)
    {
        std::string ligne ;
        while(std::getline(fichier,ligne))
        {
            std::istringstream it(ligne) ;
            int numero ;
            it >> numero ;

            Membres membre(it) ;

            m_membres.insert(std::make_pair(numero,membre)) ;
        }
        fichier.close() ;
    }
    else
        std::cerr << "Erreur à l'ouverture des membres" << std::endl ;
}

void Bibliotheque::sauvegardeBiblio(std::string cheminBiblio)
{
    std::ofstream fichier(cheminBiblio.c_str()) ;
    if(fichier)
    {
        for(std::map<int,Livre>::iterator it = m_biblio.begin(); it != m_biblio.end(); ++it)
        {
            fichier << it->first << " " << m_estEmprunte[it->first];
            fichier << it->second ;
        }
    }
    else
        std::cerr << "Erreur à l'ouverture lors de l'ecriture" << std::endl ;
}

void Bibliotheque::sauvegardeMembres(std::string cheminMembres)
{
    std::ofstream fichier(cheminMembres.c_str()) ;
    if(fichier)
    {
        for(std::map<int,Membres>::iterator it = m_membres.begin(); it != m_membres.end(); ++it)
        {
            fichier << it->first ;
            fichier << it->second ;
        }
    }
    else
        std::cerr << "Erreur à l'ouverture lors de l'ecriture" << std::endl ;
}

int Bibliotheque::getNombreLivre() const
{
    return m_biblio.size() ;
}

int Bibliotheque::livreExiste(int numero)
{
    std::map<int,Livre>::iterator it = m_biblio.find(numero) ;
    if(it != m_biblio.end())
        return it->first ;
    else
        return 0 ;
}

void Bibliotheque::ajouterLivre()
{
    int numero(0) ;
    std::string titre, auteur, genre ;

    std::cout << std::endl << "Ajout d'un nouveau livre :" << std::endl ;

    saisir_int(numero, "Veuillez entrer le numero :  ") ;
    while(livreExiste(numero))
    {
        std::cout << "Le numero existe deja" << std::endl ;
        saisir_int(numero, "Veuillez entrer le numero :  ") ;
    }

    saisir_string(titre, "Veuillez entrer le titre :  ") ;
    saisir_string(auteur, "Veuillez entrer l'auteur :  ") ;
    saisir_string(genre, "Veuillez entrer le genre :  ") ;

    m_biblio.insert(std::make_pair(numero,Livre(titre,auteur,genre))) ;
    std::cout << "Le livre " << numero << " a ete ajoute" << std::endl ;
}

void Bibliotheque::supprimerLivre()
{
    int numero(0) ;
    std::cout << std::endl << "Suppression d'un livre :" << std::endl ;
    saisir_int(numero, "Veuillez entrer le numero :  ") ;
    if(livreExiste(numero))
    {
        m_biblio.erase(numero) ;
        std::cout << "Le livre numero " << numero << " a ete supprime" << std::endl ;
    }
    else
        std::cout << "Le livre n'existe pas!" << std::endl ;
}

void Bibliotheque::afficherLivre(int numero)
{
    if(!numero)
    {
        std::cout << std::endl ;
        saisir_int(numero, "Veuillez entrer le numero du livre a afficher:  ") ;
        std::cout << std::endl ;
    }
    if(livreExiste(numero))
    {
        std::cout << std::setw(11) << std::left << "Numero" << ":" << std::setw(15) << std::right << numero << std::endl ;
        std::cout << std::setw(11) << std::left << "Disponible" << ":" << std::setw(15) << std::right << std::boolalpha << !m_estEmprunte[numero] << std::endl ;
        std::cout << m_biblio[numero] << std::endl ;
    }
    else
        std::cerr << "Le livre n'existe pas!" << std::endl ;
}

void Bibliotheque::afficherBibliotheque()
{
    std::cout << std::endl ;
    for(std::map<int,Livre>::iterator it = m_biblio.begin() ; it != m_biblio.end() ; it++)
    {
        std::cout << std::setw(11) << std::left << "Numero" << ":" << std::setw(15) << std::right << it->first << std::endl ;
        std::cout << std::setw(11) << std::left << "Disponible" << ":" << std::setw(15) << std::right << std::boolalpha << !m_estEmprunte[it->first] << std::endl ;
        std::cout << it->second << std::endl ;
    }
}

void Bibliotheque::afficherEmprunt()
{
    std::cout << std::endl << "Liste des livres empruntes:" << std::endl ;
    for(std::map<int,bool>::iterator it = m_estEmprunte.begin() ; it != m_estEmprunte.end() ; it++)
    {
        if(it->second)
        {
            afficherLivre(it->first) ;
        }
    }
}

void Bibliotheque::afficherLivreMembre()
{
    int numero(0) ;
    std::cout << std::endl ;
    while(m_membres.find(m_biblio[numero].getIdEmprunt()) == m_membres.end() )
        saisir_int(numero, "Saisir Id du membre :  ") ;

    std::cout << std::endl << "Liste des livres empruntes:" << std::endl ;
    for(std::map<int,bool>::iterator it = m_estEmprunte.begin() ; it != m_estEmprunte.end() ; it++)
    {
        if(it->second && m_biblio[it->first].getIdEmprunt() == numero )
        {
            afficherLivre(it->first) ;
        }
    }
}

void Bibliotheque::modifierLivre()
{
    int numero(0) ;
    std::cout << std::endl ;
    saisir_int(numero, "Numero du livre a modifier :  ") ;
    std::cout << std::endl ;
    if(livreExiste(numero))
    {
        int choix(0) ;
        std::cout << "Que voulez-vous modifier : " << std::endl << std::endl << \
                     "1. Titre " << std::endl << \
                     "2. Auteur " << std::endl << \
                     "3. Genre " << std::endl << \
                     "4. Date Emprunt " << std::endl << \
                     "5. Date Retour " << std::endl << \
                     "6. ID Emprunteur " << std::endl << \
                     "7. Retour Menu Principal " << std::endl << std::endl ;

        if ( saisir_int(choix, "Votre choix :  "))
        {
            switch(choix)
            {
                case 1:
                    m_biblio[numero].setTitre() ;
                    break ;
                case 2:
                    m_biblio[numero].setAuteur() ;
                    break ;
                case 3:
                    m_biblio[numero].setGenre() ;
                    break ;
                case 4:
                    m_biblio[numero].setEmprunt() ;
                    break ;
                case 5:
                    m_biblio[numero].setRetour() ;
                    break ;
                case 6 :
                    while(m_membres.find(m_biblio[numero].getIdEmprunt()) == m_membres.end() )
                        m_biblio[numero].setIdEmprunt() ;
                    break ;
                case 7:
                    break ;
            }
        }
    }
    else
        std::cout << "Le livre n'existe pas" << std::endl ;
}

void Bibliotheque::emprunter()
{
    int numero(0) ;
    std::cout << std::endl ;
    saisir_int(numero, "Numero du livre a emprunter :  ") ;

    if(livreExiste(numero) && !m_estEmprunte[numero])
    {
        m_estEmprunte[numero] = true ;
        m_biblio[numero].setEmprunt(Date::dateActuelle()) ;
        while(m_membres.find(m_biblio[numero].getIdEmprunt()) == m_membres.end() )
            m_biblio[numero].setIdEmprunt() ;
    }
    else
        std::cout << "Le livre n'existe pas ou est deja emprunte" << std::endl ;
}

void Bibliotheque::retour()
{
    int numero(0) ;
    std::cout << std::endl ;
    saisir_int(numero, "Numero du livre a rendre :  ") ;
    if(livreExiste(numero) && m_estEmprunte[numero])
    {
        m_estEmprunte[numero] = false ;
        m_biblio[numero].setRetour(Date::dateActuelle()) ;
    }
    else
        std::cerr << "Le livre n'existe pas ou est deja rendu" << std::endl ;
}

void Bibliotheque::ajouterMembre()
{
    std::string nom, prenom ;

    std::cout << std::endl << "Ajout d'un nouveau membre :" << std::endl ;

    saisir_string(nom, "Veuillez entrer le nom :  ") ;
    saisir_string(prenom, "Veuillez entrer le prenom :  ") ;

    m_membres.insert(std::make_pair(m_membres.end()->first+1,Membres(nom,prenom))) ;
    std::cout << "Le membre " << std::endl << m_membres[m_membres.end()->first] << " a ete ajoute" << std::endl ;
}

void Bibliotheque::bouclePrincipale()
{
    std::cout << "Bienvenue dans Biblio++" << std::endl ;
    bool termine(false) ;
    int choix(0) ;

    while(!termine)
    {
        std::cout << std::endl << "   MENU PRINCIPAL  " << std::endl << std::endl << \
                     "1. Ajouter un livre " << std::endl << \
                     "2. Supprimer un livre " << std::endl << \
                     "3. Modifier un livre " << std::endl << \
                     "4. Afficher un livre " << std::endl << \
                     "5. Afficher la bibliotheque " << std::endl << \
                     "6. Emprunter un livre " << std::endl << \
                     "7. Rendre un livre " << std::endl << \
                     "8. Afficher les livres empruntes " << std::endl << \
                     "9. Ajouter un membre " << std::endl << \
                     "10. Afficher livre emprunte par un membre " << std::endl << \
                     "11. Quitter " << std::endl << std::endl ;

        if( saisir_int(choix,"Votre choix :  ") )
        {
            switch(choix)
            {
                case 1 :
                    ajouterLivre() ;
                    break ;
                case 2 :
                    supprimerLivre() ;
                    break ;
                case 3 :
                    modifierLivre() ;
                    break ;
                case 4 :
                    afficherLivre() ;
                    break ;
                case 5 :
                    afficherBibliotheque() ;
                    break ;
                case 6 :
                    emprunter() ;
                    break ;
                case 7 :
                    retour() ;
                    break ;
                case 8 :
                    afficherEmprunt() ;
                    break ;
                case 9 :
                    ajouterMembre() ;
                    break ;
                case 10 :
                    afficherLivreMembre() ;
                    break ;
                case 11 :
                    termine = true ;
                    break ;
            }
        }
    }
}

La methode bouclePrincipale() appel les autres méthodes selon les actions de l'utilisateur.

fichier Livre.h

#ifndef LIVRE_H
#define LIVRE_H

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <iomanip>
#include "Date.h"
#include "inputs.h"

class Livre
{
    public:
        Livre() ;
        Livre(std::string titre, std::string auteur, std::string genre);
        Livre(std::istringstream &it) ;
        virtual ~Livre();

        void ecritureFichier(std::ofstream &flux) const ;
        void afficher(std::ostream &flux) const ;

        void setTitre() ;
        void setAuteur() ;
        void setGenre() ;
        void setEmprunt(Date date = Date(0,0,0)) ;
        void setRetour(Date date = Date(0,0,0)) ;
        void setIdEmprunt() ;

        int getIdEmprunt() const ;

    private:
        std::string m_auteur ;
        std::string m_titre ;
        std::string m_genre ;
        Date m_emprunt ;
        Date m_retour ;
        int m_idEmprunt ;
};

std::ofstream &operator<<(std::ofstream &flux, Livre const& livre) ;
std::ostream &operator<<(std::ostream &flux, Livre const& livre) ;

#endif // LIVRE_H

fichier Livre.cpp

#include "Livre.h"

Livre::Livre() {}

Livre::Livre(std::string titre, std::string auteur, std::string genre) :
    m_auteur(auteur), m_titre(titre), m_genre(genre), m_idEmprunt(0) {}

Livre::Livre(std::istringstream &it)
{
    it >> m_idEmprunt ;

    std::getline(it,m_titre, '/') ;
    std::getline(it,m_titre, '/') ;
    std::getline(it,m_auteur, '/') ;
    std::getline(it,m_genre, '/') ;

    std::string date ;
    std::getline(it,date, '/') ;
    m_emprunt = Date(date) ;
    std::getline(it,date, '/') ;
    m_retour = Date(date) ;
}

Livre::~Livre() {}

void Livre::ecritureFichier(std::ofstream &flux) const
{
    flux << " " << m_idEmprunt << "/" << m_titre << "/" << m_auteur << "/" << m_genre << "/" ;
    flux << m_emprunt << "/" ;
    flux << m_retour << std::endl ;
}

void Livre::afficher(std::ostream &flux) const
{
    flux << std::setw(11) << std::left << "Titre" << ":" << std::setw(15) << std::right << m_titre << std::endl ;
    flux << std::setw(11) << std::left << "Auteur" << ":" << std::setw(15) << std::right << m_auteur << std::endl ;
    flux << std::setw(11) << std::left << "Genre" << ":" << std::setw(15) << std::right << m_genre << std::endl ;
    flux << std::setw(11) << std::left << "Emprunt" << ":" << m_emprunt << std::endl ;
    flux << std::setw(11) << std::left << "IDemprunt" << ":" << std::setw(15) << std::right << m_idEmprunt << std::endl ;
    flux << std::setw(11) << std::left << "Retour" << ":" << m_retour << std::endl ;
}

void Livre::setAuteur()
{
    std::string texte ;
    std::cout << std::endl ;
    saisir_string(texte," Veuillez saisir l'auteur : ") ;
    m_auteur = texte ;
}

void Livre::setGenre()
{
    std::string texte ;
    std::cout << std::endl ;
    saisir_string(texte," Veuillez saisir le genre : ") ;
    m_genre = texte ;
}

void Livre::setTitre()
{
    std::string texte ;
    std::cout << std::endl ;
    saisir_string(texte," Veuillez saisir le titre : ") ;
    m_titre = texte ;
}

void Livre::setEmprunt(Date date)
{
    if(date == Date(0,0,0))
    {
        unsigned int jour, mois, annee ;
        std::cout << std::endl ;
        saisir_uint(jour, "Veuillez saisir le jour :");
        saisir_uint(mois, "Veuillez saisir le mois :");
        saisir_uint(annee, "Veuillez saisir l'annee :");
    }
    m_emprunt = date ;
}

void Livre::setRetour(Date date)
{
    if(date == Date(0,0,0))
    {
        unsigned int jour, mois, annee ;
        std::cout << std::endl ;
        saisir_uint(jour, "Veuillez saisir le jour :");
        saisir_uint(mois, "Veuillez saisir le mois :");
        saisir_uint(annee, "Veuillez saisir l'annee :");
    }
    m_retour = date ;
}

void Livre::setIdEmprunt()
{
    int idEmprunt ;
    std::cout << std::endl ;
    saisir_int(idEmprunt," Veuillez saisir l'ID de l'emprunteur : ") ;
    m_idEmprunt = idEmprunt ;
}

int Livre::getIdEmprunt() const
{
    return m_idEmprunt ;
}

std::ofstream &operator<<(std::ofstream &flux, Livre const& livre)
{
    livre.ecritureFichier(flux) ;
    return flux ;
}

std::ostream &operator<<(std::ostream &flux, Livre const& livre)
{
    livre.afficher(flux) ;
    return flux ;
}

Cette classe contient essentiellement les accesseurs pour modifier et afficher les livres.

fichier Membres.h

#ifndef MEMBRES_H
#define MEMBRES_H

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <iomanip>

class Membres
{
    public:
        Membres();
        Membres(std::string nom, std::string prenom);
        Membres(std::istringstream &it) ;
        virtual ~Membres();

        void ecritureFichier(std::ofstream &flux) const ;
        void afficher(std::ostream &flux) const ;

    private:
        std::string m_nom ;
        std::string m_prenom ;
};

std::ofstream &operator<<(std::ofstream &flux, Membres const& membre) ;
std::ostream &operator<<(std::ostream &flux, Membres const& membre) ;

#endif // MEMBRES_H

fichier Membres.cpp

#include "Membres.h"

Membres::Membres() {}

Membres::Membres(std::string nom, std::string prenom) :
    m_nom(nom), m_prenom(prenom) {}


Membres::Membres(std::istringstream &it)
{
    std::getline(it,m_nom, '/') ;
    std::getline(it,m_nom, '/') ;
    std::getline(it,m_prenom, '/') ;
}

Membres::~Membres() {}

void Membres::ecritureFichier(std::ofstream &flux) const
{
    flux << "/" << m_nom << "/" << m_prenom << std::endl ;
}

void Membres::afficher(std::ostream &flux) const
{
    flux << std::setw(11) << std::left << "Nom" << ":" << std::setw(15) << std::right << m_nom << std::endl ;
    flux << std::setw(11) << std::left << "Prenom" << ":" << std::setw(15) << std::right << m_prenom << std::endl ;
}

std::ofstream &operator<<(std::ofstream &flux, Membres const& membre)
{
    membre.ecritureFichier(flux) ;
    return flux ;
}

std::ostream &operator<<(std::ostream &flux, Membres const& membre)
{
    membre.afficher(flux) ;
    return flux ;
}

De la même façon que Livre, cette classe contient essentiellement les accesseurs et affichage des membres.

fichier Date.h

#ifndef DATE_H
#define DATE_H

#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <ctime>

class Date
{
    public:
        Date();
        Date(unsigned int jour, unsigned int mois, unsigned int annee);
        Date(std::string date) ;
        Date(Date const& date) ;
        virtual ~Date();

        void modifierJour(unsigned int jour) ;
        void modifierMois(unsigned int mois) ;
        void modifierAnnee(unsigned int annee) ;

        void ecritureFichier(std::ofstream &flux) const ;
        void afficher(std::ostream &flux) const ;
        bool estEgal(Date const& b) const ;

        static Date dateActuelle() ;

    private:
        unsigned int m_jour ;
        unsigned int m_mois ;
        unsigned int m_annee ;
};

std::ofstream &operator<<(std::ofstream &flux, Date const& date) ;
std::ostream &operator<<(std::ostream &flux, Date const& date) ;
bool operator==(Date const& date1, Date const& date2) ;

#endif // DATE_H

fichier Date.cpp

#include "Date.h"

Date::Date() :
    m_jour(0), m_mois(0), m_annee(0) {}

Date::Date(unsigned int jour, unsigned int mois, unsigned int annee) :
    m_jour(jour), m_mois(mois), m_annee(annee) {}

Date::Date(std::string date)
{
    std::istringstream it(date) ;
    it >> m_jour >> m_mois >> m_annee ;
}

Date::Date(Date const& date) :
    m_jour(date.m_jour), m_mois(date.m_mois), m_annee(date.m_annee) {}

Date::~Date() {}

void Date::modifierAnnee(unsigned int annee)
{
    m_annee = annee ;
}

void Date::modifierMois(unsigned int mois)
{
    m_mois = mois ;
}

void Date::modifierJour(unsigned int jour)
{
    m_jour = jour ;
}

void Date::ecritureFichier(std::ofstream &flux) const
{
    flux << std::setw(2) << std::setfill('0') << m_jour << " " << \
            std::setw(2) << std::setfill('0') << m_mois << " " << \
            std::setw(4) << std::setfill('0') << m_annee ;
}

void Date::afficher(std::ostream &flux) const
{
    std::ostringstream it ;
    it << std::setw(2) << std::setfill('0') << m_jour << "_" << \
          std::setw(2) << std::setfill('0') << m_mois << "_" << \
          std::setw(4) << std::setfill('0') << m_annee << std::setfill(' ');

    flux << std::setw(15) << std::right << it.str() ;
}

bool Date::estEgal(Date const& b) const
{
    return(m_jour == b.m_jour && m_mois == b.m_mois && m_annee == b.m_annee) ;
}

Date Date::dateActuelle()
{
    time_t rawtime;
    struct tm * timeinfo;
    char buffer [80];

    time (&rawtime);
    timeinfo = localtime(&rawtime);

    strftime (buffer,80,"%d %m %Y",timeinfo);
    Date date(buffer) ;
    return date ;
}

std::ofstream &operator<<(std::ofstream &flux, Date const& date)
{
    date.ecritureFichier(flux) ;
    return flux ;
}

std::ostream &operator<<(std::ostream &flux, Date const& date)
{
    date.afficher(flux) ;
    return flux ;
}

bool operator==(Date const& a, Date const& b)
{
    return a.estEgal(b) ;
}

Gère les Dates et leurs affichages.

fichier Inputs.h

#ifndef INPUTS_H_INCLUDED
#define INPUTS_H_INCLUDED

#include <string>
#include <iostream>
#include <cstdlib>
#include <sstream>

bool saisir_string(std::string &variable, const std::string &message) ;
bool saisir_int(int &variable, const std::string &message) ;
bool saisir_uint(unsigned int &variable, const std::string &message) ;

#endif // INPUTS_H_INCLUDED

fichier inputs.cpp

#include "inputs.h"

using namespace std;

bool saisir_string(string &variable, const string &message)
{
    while(true)
    {
        cout << message;

        getline(cin, variable);

        if(cin.bad() || cin.eof())
        {
            cerr << "Erreur, saisie incorrecte." << endl;

            if(cin.eof())
                break;
        }
        else if(cin.fail())
            cerr << "Erreur, saisie incorrecte." << endl;

        break;
    }
    return true;
}

bool saisir_int(int &variable, const string &message)
{
    string temp;

    while(saisir_string(temp, message))
    {
        istringstream stream(temp);
        stream >> variable;

        if(stream.fail() || !stream.eof())
            cerr << "Erreur, saisie incorreecte." << endl;
        else
            return true;
    }
    return false;
}

bool saisir_uint(unsigned int &variable, const std::string &message)
{
    string temp;

    while(saisir_string(temp, message))
    {
        istringstream stream(temp);
        stream >> variable;

        if(stream.fail() || !stream.eof())
            cerr << "Erreur, saisie incorreecte." << endl;
        else
            return true;
    }
    return false;
}

Comme je l'ai dit précédemment les fonctions inputs proviennent du tuto de saisie sécurisé de ooprog.

Voila, j’espère qu'il y aura quelques courageux qui arriveront à me lire pour me faire des commentaires.

Merci d'avance!











  • Partager sur Facebook
  • Partager sur Twitter
18 novembre 2015 à 8:44:37

Lu'!

Quand tu as beaucoup de code, il est préférable de le mettre sur un dépôt type github pour permettre une lecture plus aisée. De plus, quand tu veux demander des commentaires sur un exercice, il est préférable d'ouvrir un nouveau sujet.

Concernant ton code, d'un point de vue conception :

  • les livres, la bibliothèque, les membres sont des éléments à sémantique d'entité, ils doivent donc respecter la forme associée,
  • leurs contructeurs par défaut n'ont aucun sens,
  • la boucle principale n'a rien à faire dans bibliothèque,
  • la bibliothèque à trop de tâches différentes, elle s'occupe à la fois de manipuler les livres et les membres, c'est trop,
  • les setters sur ton livre sont crados (Why setters and getters are evil ? Loi de Demeter),
  • la duplication ecritureStream + operator<< et lectureStream + operator>> est une (des multiples) connerie montrée par le cours moisi d'OC, ça multiplie les éléments de l'interface et ruine l'ISP (principes SOLID),
  • un Emprunt et un Livre sont deux choses différentes (et doivent donc bénéficier chacune d'une classe),
  • les modifieurs (= setters) de Date sont crados,
  • un peu de programmation par contrat ?

D'un point de vue implémentation :

  • active C++11 ou 14 (on est en 2015),
  • du coup plus besoin de "c_str()" dans les déclarations des ifstream/ofstream,
  • les "fichier.close()" sont complètement inutiles, ils n'apportent rien à ton programme,
  • si la classe n'a pas vocation à être dérivée, pas la peine de mettre un destructeur virtuel,
  • quand le destructeur/constructeur utilise le comportement par défaut, autant laisser le compilateur faire le boulot,
  • une map int -> smth, serait judicieusement remplacée par un vector qui nous donne gratuitement les identifiants,
  • passe tes string par référence const,
  • quand on n'arrive pas à ouvrir un fichier dont dépend la création de l'objet, ça devrait cracher une exception,
  • quand une fonction devrait renvoyer un booléen ("existe"), pas de int,
  • quand une valeur n'a pas vocation à pouvoir être négative (taille, position, etc ...), n'utilise pas un "int", par exemple :
    int Bibliotheque::getNombreLivre() const
    {
      return m_biblio.size() ;
    }
    est un gros fail car ".size()" ne renvoie pas un int (voir la doc ...).
  • for(std::map<int,Livre>::iterator it = m_biblio.begin(); it != m_biblio.end(); ++it)
    {
      fichier << it->first << " " << m_estEmprunte[it->first];
      fichier << it->second ;
    }
    Ou plus simplement :
    for(auto& pair_livre = m_biblio)
    {
      fichier << pair_livre.first << " " << m_estEmprunte[pair_livre.first];
      fichier << pair_livre.second ;
    }
  • il faut contrôler getline,
  • on n'inclut des headers que lorsqu'ils sont nécessaires (s'il n'est pas nécessaire dans un header, il n'a rien à faire là et doit être inclus dans le source uniquement).

Voilà, il y a déjà du boulot et tu t'en épargneras en utilisant un cours de C++ correct.

-
Edité par Ksass`Peuk 18 novembre 2015 à 9:53:05

  • Partager sur Facebook
  • Partager sur Twitter
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
18 novembre 2015 à 18:44:01

Salut Ksass,

Merci pour tous les commentaires et conseil. Je vais essayer de retravailler tous ça.

En dehors des liens que tu m'as donnée (qui vont déjà me faire pas mal de lecture) est ce que tu aurais un livre "correct" de C++ à conseiller?

  • Partager sur Facebook
  • Partager sur Twitter
18 novembre 2015 à 18:52:54

  • le cours en ligne de @gbdivers (en cours d'écriture), pour les problèmes liés à des incompréhensions qui ne sont dues à un manque d'étude ou juste une difficulté de ton côté, il y a ce post de forum pour répertorier, sinon il y a le forum pour poster tes question,
  • le livre C++ Primer, dans sa dernière édition.
  • Partager sur Facebook
  • Partager sur Twitter
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
2 janvier 2017 à 20:18:07

Salut a tous!

je voudrais réaliser une petit jeu, voici son principe :

- tirer un mot aléatoire dans un dictionnaire compose d'une centaine de mots,

-le donner a l'utilisateur en désordre; il doit trouver le mot correct en écrivant ce mot quand on lui aura demandé,

-compter le nombre de coups : passé 10 essais on lui affiche la réponse;

-compter le nombre de fois : au terme des cinq premiers tours on lui affiche son score sur 5;

-on lui redemande s'il veut encore jouer une autre partie par oui ou non.

*Voici le lien du dictionnaire à télécharger.

J'ai vraiment beaucoup essayé ce exercice mais le dictionnaire m'a loupé et le comptage de coups et je me rends aussi compte que sur presque tous les exercices que je cherche sur Internet je retrouve toujours ces bêtes de drôle.

Je veux aussi quelques petites explications pour mieux comprendre le code via des commentaires ou a la fin mais c'est mieux avec des commentaires, je remercierai vraiment la personne qui m'aidera a résoudre cet exercice.

Merci d'avance.

-
Edité par StephaneWamba 2 janvier 2017 à 20:22:22

  • Partager sur Facebook
  • Partager sur Twitter
6 janvier 2017 à 14:57:35

Bonjour StephaneWamba

je te conseillerais de suivre ce cours : 

https://openclassrooms.com/courses/programmez-avec-le-langage-c

Tu y trouveras beaucoup de choses intéressantes, ainsi que la réponse a ta question.

-
Edité par Kelerm 6 janvier 2017 à 14:59:32

  • Partager sur Facebook
  • Partager sur Twitter
6 janvier 2017 à 15:01:27

C'est plutôt amusant de conseiller un cours de C++ dont on explique en long, en large et en travers sur le forum qu'il est obsolète et apprends un paquet de trucs à ne surtout pas faire, en particulier quand on débute.

  • Partager sur Facebook
  • Partager sur Twitter
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
6 janvier 2017 à 15:30:53

Merci pour ton information, car je ne parcours pas le forum en long, en large et en travers.

Cependant je ne suis pas sur que ton intervention va aider Stephane.

Et la réponse a sa question ce trouve en partie dans le lien que je lui ai suggéré, de plus si ce cours est tout pouris comme tu le signale il faudrais peut être qu'il soit retiré.

  • Partager sur Facebook
  • Partager sur Twitter

[Exercices] Venez vous entraîner !

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
  • Editeur
  • Markdown