Mon crypteur est vim qui applique un tr de base. Et puis, quel est le sens de rotationner à 13 les caractères hors de la plage des 26 lettres standards ?
(nous ne sommes pas complètement HS, écrire tr ou rot pourraient être des exos pour ceux qui font du C ^^')
Je serais surpris qu'il n'ait pas connaissance de cette suite de bibliothèques qui booste notre productivité.
C'est bien tourné, tu aurais même pu dire que tu serais rationnellement surpris que Nanoc n'ait pas connaissance de cette suite de bibliothèques qui booste notre productivité .
Citation : lmghs
vy l n har pynffr qr zêzr pbzcyrkvgé qnaf yn ovoyvbguèdhr fgnaqneq
Je serais surpris qu'il n'ait pas connaissance de cette suite de bibliothèques qui booste notre productivité.
C'est bien tourné, tu aurais même pu dire que tu serais rationnellement surpris que Nanoc n'ait pas connaissance de cette suite de bibliothèques qui booste notre productivité .
Non, le but de mon message était d'être encore plus précis que celui de lmghs en jouant sur un mot. Mais c'est vrai qu'on n'aurait pu prendre le message comme ironique, je ferais plus attention la prochaine fois.
En fait après avoir relu la phrase dans son contexte original (c'est à dire de façon à faire passer un message à l'aide d'un gros sous entendu) j'ai compris l'intention de ton message. C'est le fait que ça soit cité hors contexte qui m'a perturbé ainsi que des années de lecture de forum (plus ou moins sérieux d'ailleurs) où la plus part du temps si quelqu'un fait des phrases un tant soit peu bien tourné il se retrouve traité soit d'usurpateur, soit de crâneur, soit de vieux jeu xD. j'ai donc sur le coup pensé que ton message était de ce genre là.
Je serais surpris qu'il n'ait pas connaissance de cette suite de bibliothèques qui booste notre productivité.
C'est bien tourné, tu aurais même pu dire que tu serais rationnellement surpris que Nanoc n'ait pas connaissance de cette suite de bibliothèques qui booste notre productivité .
Et moi je me tapes sur les doigts parce que j'y pense jamais assez souvent! [Le nombre de choses à côté desquelles je suis passé est à se rendre fou!]
Je crois que je vais changer d'écran pour un de leur logo....
Mon crypteur est vim qui applique un tr de base. Et puis, quel est le sens de rotationner à 13 les caractères hors de la plage des 26 lettres standards ?
(nous ne sommes pas complètement HS, écrire tr ou rot pourraient être des exos pour ceux qui font du C ^^')
Non, mais cela fait juste foirer mon décrypteur qui ne s'y attendait pas.
@Chlab_lak: Le seul défaut de la classe que tu proposes c'est que c'est pas un concept mathématique évident pour tout le monde. Mais il est vrai qu'il y a peu de différences.
@Chlab_lak: Le seul défaut de la classe que tu proposes c'est que c'est pas un concept mathématique évident pour tout le monde. Mais il est vrai qu'il y a peu de différences.
Non, je demandais juste quelle était la classe donc parlait lmghs ici => "vy l n har pynffr qr zêzr pbzcyrkvgé qnaf yn ovoyvbguèdhr fgnaqneq" (moi même je n'ai pas encore vu ça à l'école (je ne suis même pas sûr que c'est au programme), donc je vais pas le proposer comme exo). Sur ce, bonne chance aux candidats.
Juste deux questions avant que je ne finalise mon code :
1) Pour l'opérateur puissance (^), est-il vraiment correct dans ce contexte ?
Les puissances rationnelles peuvent renvoyer des irrationnels (je pense aux puissances non entières comme 1/2), qu'on ne peut pas représenter sous forme de fraction...
2) Ce n'était pas demandé, mais je ne vois vraiment comment implémenter proprement l'opérateur d'extraction de flux, de telle sorte que, comme lorsqu'on extrait un entier par exemple, il s'arrête au premier caractère incorrect...
Un peu d'aide de ce côté ?
Merci !
EDIT : mouarf, la première question était bête, je suppose que tu ne parlais d'implémenter cet opérateur que pour les entiers, pas entre fractions .
1) Oui je parle que des puissances entières et positives. Sinon, on arrive vite à des (gros) problèmes mathématiques. On doit pouvoir faire par exemple: <math>\((\frac{2}{3})^5\)</math>
2) Je te laisse chercher un moment encore. Crée un nouveau thread si tu n'y arrives pas.
je remarque (au passage) que ça fait plus de trois jour que sur la page 1, on marque la correction des exercices "des chiffres" et "des lettre" pour "demain" ... c'est un long demain alors !
les deux exercices sont sympas alors vivement la correction !
encore merci nanoc
Pour la conversion du double en fraction je me suis posé la même question que toi. J'ai trouvé une solution (pas forcément élégante...).
De manière basique, j'utilise la fonction fmod pour isoler la partie décimale du double et je multiplie par des puissances de dix, jusqu'à obtenir un nombre entier que je transforme en fraction et que j'ajoute à la partie entière du double. A toi de chercher pour la suite...
Super idée que ces exercices, nouveau sur le site j'apprécie vraiment... Merci Nanoc!...
Bonjour tout le monde ! Il est temps que je dévoile une solution pour l'exercice du mois de septembre. Vous avez été 14 à m'envoyer une solution.
Cependant, aucune des solutions proposées me satisfaisaient pleinement. Je vous fais donc part de ma solution.
Partie "Papier-Crayon"
Cet exercice est principalement un exercice d'algorithmique. Il est donc nécessaire de passer par une partie de réflexion avant de se lancer dans la rédaction sinon, on est sûr de se perdre en cours de route.
On peut décomposer le problème en 2 parties différentes, la création d'un tirage et la recherche d'une solution.
Création d'un tirage
Cette partie n'est pas trop complexe. Il faut demander à l'utilisateur si il souhaite une consonne ou une voyelle et tirer au hasard une lettre en conséquence. Il faut penser à compter le nombre de voyelles pour s'assurer qu'il y en ait au moins 2 dans le tirage. Si après 7 lettres, le joueur n'a pas choisi de tirer une voyelle, il faut le forcer à en tirer deux pour obtenir un tirage valide.
Recherche de la solution
Là c'est plus compliqué. Je vous présente la solution la plus simple mais qui n'est pas la plus efficace. On peut faire plus rapide, mais cela demande beaucoup de travail et comme vous pourrez le voir, la solution proposée s'exécute de manière quasi-instantannée.
Quand est-ce qu'un mot du dictionnaire est valide (c'est-à-dire écrivable avec les lettres du tirage) ?
Il faut qu'il remplisse les deux conditions suivantes:
1) Le mot doit ne doit contenir aucune lettre qui n'est PAS dans le tirage.
2) Chaque lettre du tirage doit être utilisée au maximum une seule fois.
Si le mot contient un (ou des tirets), il faut les ignorer puisque le tirage ne peut pas contenir ce symbole.
Finalement, si un mot fait plus que 9 lettres (sans les tirets) il ne peut pas être valide puisqu'il aura trop de lettres.
Armé de tout cela, on peut écrire un algorithme comme suit:
POUR TOUS LES MOTS DU FICHIER
SI la taille du mot > 9, on SAUTE au mot suivant
POUR TOUTES LES LETTRES DU MOT
SI la lettre n'est pas dans le tirage, on SAUTE au mot suivant
FIN POUR TOUT
On sauvegarde le mot
FIN POUR TOUT
Il faudra encore ajouter le traitement spécial pour les tirets.
Choix des structures de données
Dans ce problème, nous devons manipuler des chaines de caractères, nous allons donc utiliser des std::string.
Nous aurons également besoin d'un tableu de chaines de caractère pour contenir les solutions. Le plus simple est un std::vector<std::string>. Comme cela prend de la place à écrire et que le programmeur se doit d'être paresseux, on utilisera un petit typedef.
typedef std::vector<std::string> Tableau;
Programmation
Il est maintenant temps de passer à la partie "codage" de l'exercice.
Pour le tirage, il va falloir obtenir des nombres aléatoires afin d'obtenir des lettres aléatoires. Nous allons donc définir une chaîne VOYELLE: conststringVOYELLES="aeiouy";
Il faudra tirer au hasard un nombre dans entre 0 et VOYELLES.size() non-compris. Comme il faut faire la même chose pour les consonnes, il vaut mieux écrire une fonction qui tire un nombre entre MIN et MAX.
//Fonction qui renvoit un entier au hasard entre min et max
unsigned int hasard(unsigned int min,unsigned int max)
{
const double x = static_cast<double>(rand())/RAND_MAX;
return static_cast<unsigned int>(x * (max-min))+ min;
}
Les static_cast<int> sont l'équivalent C++ des trantypages C comme par exemple:
//Fonction qui renvoit un entier au hasard entre min et max
unsigned int hasard(unsigned int min,unsigned int max)
{
const double x = (double)(rand())/RAND_MAX;
return (unsigned int)(x * (max-min))+ min;
}
En faisant hasard(0,VOYELLES.size()), on obtient une position auhasard dans la chaine VOYELLES qui nous donne donc accès à une voyelle au hasard.
On peut maintenant utiliser cette fonction pour créer un tirage en demandant à l'utilisateur si il veut choisir une voyelle ou une consonne. Le code est commenté de sorte à expliquer en détail chaque ligne.
//Les constantes du programme
const string VOYELLES = "aeiouy";
const string CONSONNES = "bcdfghjklmnpqrstvwxz";
const string DICTIONNAIRE = "liste_finale.txt";
const unsigned int NB_VOYELLES = VOYELLES.size();
const unsigned int NB_CONSONNES = CONSONNES.size();
//Les constantes du jeu
const unsigned int TAILLE_TIRAGE = 9;
const unsigned int NB_MINIMAL_VOYELLES = 2;
//Fonction qui renvoit un tirage aleatoire
string creerTirage()
{
string tirage;
char choix,tire;
unsigned int nbVoyelles(0);
//On cree un tirage de TAILLE_TIRAGE caracteres
for (unsigned int i(0);i<TAILLE_TIRAGE;++i)
{
//Test pour le cas particulier ou il n'y a ps assez de voyelles
if (i>=TAILLE_TIRAGE - NB_MINIMAL_VOYELLES + nbVoyelles && nbVoyelles<NB_MINIMAL_VOYELLES)
{
tire = VOYELLES[hasard(0,NB_VOYELLES)];
cout << "Le tirage necessite un minimum de 2 voyelles" << endl;
++nbVoyelles;
}
else //Cas normal
{
//On demande a l'utilisateur son choix
cout << "Lettre numero " << i+1 << ": Consonne ou Voyelle [c/v] ?: " << flush;
//On recupere son choix et on purge le flux au cas ou l'utilisateur a entre n'importe quoi
cin >> choix;
cin.clear();
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
//Selon le choix, on tire la lettre voulue
if (choix == 'c')
{
tire = CONSONNES[hasard(0,NB_CONSONNES)];
}
else if (choix == 'v')
{
tire = VOYELLES[hasard(0,NB_VOYELLES)];
++nbVoyelles;
}
else //On affiche un message d'erreur si il faut
{
cout << "ERREUR: Choix interdit. Entrez 'c' ou 'v'" << endl;
--i; //On decremente i de sorte a redemander la meme lettre
continue;
}
}
//On affiche la lettre tiree et on l'ajoute au tirage
cout << "Lettre tiree: " << tire << endl;
tirage += tire;
}
//On renvoit le tirage
return tirage;
}
Pour ce qui est de la recherche de solution appropriée, on va utiliser l'algorithme présenté plus haut en ajoutant une petite astuce pour le cas spécial des mots avec des tirets.
//Fonction qui cherche le meilleur mot dans le dictionnaire et renvoit les solutions dans un tableau
Tableau chercher(const string& tirage)
{
//On ouvre le fichier-dictionnaire en lecture
ifstream fichier(DICTIONNAIRE.c_str());
//On cree un tableau de chaines qui contiendra tous les mots corrects
Tableau solution;
//Nombre de lettres du mot le plus long actuellement trouve
unsigned int motLePlusLong(0);
//Le mot courant
string mot;
//On lit chaque mot du fichier
while (getline(fichier,mot))
{
//On calcule nombre de lettres
unsigned int nbLettres= mot.size();
//On compte les tirets dans le mot
unsigned int nbTirets(0);
unsigned int posTiret(0);
while(mot.find('-',posTiret) != string::npos) //Tant qu'il y a un tiret dans le mot a partir de la position courante
{
posTiret = mot.find('-',posTiret)+1; //On recupere la position pour la prochaine recherche
++nbTirets; //Et on incremente le compteur
}
//On soustrait au nombre de lettres le nombre de tirets puisque le tirage n'a pas de tirets
nbLettres-=nbTirets;
//Si le mot a trop de lettres, on passe au suivant puisque il ne peut pas etre solution
if (nbLettres > TAILLE_TIRAGE )
continue;
//On cree un tableau qui permet d'indiquer si chacune des lettres du tirage est utilisee
bool utilisee[TAILLE_TIRAGE]={false};
//On commence par supposer que l'on peut ecrire le mot a partir du tirage
bool motvalide=true;
//On parcourt les lettres du mot
for ( unsigned int i=0; i<mot.size(); i++ )
{
//Si c'est un tiret on saute a la lettre suivante puisqu'on a pas de tiret dans le tirage
if(mot[i] == '-')
continue;
//On commence par supposer que la lettre du mot n'est PAS dans le tirage
bool lettrevalide=false;
//On parcourt les lettres du tirage
for (unsigned int j=0; j<tirage.size(); ++j )
{
//Si la lettre du tirage correspond a la lettre du mot ET qu'on a pas encore utilise cette lettre du tirage
if ( mot[i]==tirage[j] && utilisee[j]==false )
{
//On montre que la lettre a ete utilisee
utilisee[j]=true;
//Et on valide la lettre
lettrevalide=true;
//On sort de la boucle pour passer a la lettre suivante du mot
break;
}
}
//Si une lettre est non-valide le mot est non valide donc on passe au mot suivant
if ( !lettrevalide )
{
motvalide=false;
break;
}
}
//Si le mot est valide
if (motvalide)
{
//Si on a un mot avec le meme nombre de lettres
if (nbLettres == motLePlusLong)
{
solution.push_back(mot); //On le stocke
}
else if (nbLettres > motLePlusLong) //Si le mot a plus de lettres
{
solution.clear(); //On vide le tableau
solution.push_back(mot); //Et on met notre nouveau mot
motLePlusLong = mot.size(); //On prend la taille du mot comme taille de reference
}
//Si il a moins de lettres, il nous interesse pas donc on le stocke pas
}
}
//On renvoit le tableau de mots
return solution;
}
Il n'y a plus qu'à combiner tout cela avec un main() et l'on obtient le code complet suivant:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
//Les constantes du programme
const string VOYELLES = "aeiouy";
const string CONSONNES = "bcdfghjklmnpqrstvwxz";
const string DICTIONNAIRE = "liste_finale.txt";
const unsigned int NB_VOYELLES = VOYELLES.size();
const unsigned int NB_CONSONNES = CONSONNES.size();
//Les constantes du jeu
const unsigned int TAILLE_TIRAGE = 9;
const unsigned int NB_MINIMAL_VOYELLES = 2;
//Un typedef pour simplifier la notation
typedef vector<string> Tableau;
//Fonction qui renvoit un entier au hasard entre min et max
unsigned int hasard(unsigned int min,unsigned int max)
{
const double x = static_cast<double>(rand())/RAND_MAX;
return static_cast<unsigned int>(x * (max-min))+ min;
}
//Fonction qui renvoit un tirage aleatoire
string creerTirage()
{
string tirage;
char choix,tire;
unsigned int nbVoyelles(0);
//On cree un tirage de TAILLE_TIRAGE caracteres
for (unsigned int i(0);i<TAILLE_TIRAGE;++i)
{
//Test pour le cas particulier ou il n'y a ps assez de voyelles
if (i>=TAILLE_TIRAGE - NB_MINIMAL_VOYELLES + nbVoyelles && nbVoyelles<NB_MINIMAL_VOYELLES)
{
tire = VOYELLES[hasard(0,NB_VOYELLES)];
cout << "Le tirage necessite un minimum de 2 voyelles" << endl;
++nbVoyelles;
}
else //Cas normal
{
//On demande a l'utilisateur son choix
cout << "Lettre numero " << i+1 << ": Consonne ou Voyelle [c/v] ?: " << flush;
//On recupere son choix et on purge le flux au cas ou l'utilisateur a entre n'importe quoi
cin >> choix;
cin.clear();
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
//Selon le choix, on tire la lettre voulue
if (choix == 'c')
{
tire = CONSONNES[hasard(0,NB_CONSONNES)];
}
else if (choix == 'v')
{
tire = VOYELLES[hasard(0,NB_VOYELLES)];
++nbVoyelles;
}
else //On affiche un message d'erreur si il faut
{
cout << "ERREUR: Choix interdit. Entrez 'c' ou 'v'" << endl;
--i; //On decremente i de sorte a redemander la meme lettre
continue;
}
}
//On affiche la lettre tiree et on l'ajoute au tirage
cout << "Lettre tiree: " << tire << endl;
tirage += tire;
}
//On renvoit le tirage
return tirage;
}
//Fonction qui cherche le meilleur mot dans le dictionnaire et renvoit les solutions dans un tableau
Tableau chercher(const string& tirage)
{
//On ouvre le fichier-dictionnaire en lecture
ifstream fichier(DICTIONNAIRE.c_str());
//On cree un tableau de chaines qui contiendra tous les mots corrects
Tableau solution;
//Nombre de lettres du mot le plus long actuellement trouve
unsigned int motLePlusLong(0);
//Le mot courant
string mot;
//On lit chaque mot du fichier
while (getline(fichier,mot))
{
//On calcule nombre de lettres
unsigned int nbLettres= mot.size();
//On compte les tirets dans le mot
unsigned int nbTirets(0);
unsigned int posTiret(0);
while(mot.find('-',posTiret) != string::npos) //Tant qu'il y a un tiret dans le mot a partir de la position courante
{
posTiret = mot.find('-',posTiret)+1; //On recupere la position pour la prochaine recherche
++nbTirets; //Et on incremente le compteur
}
//On soustrait au nombre de lettres le nombre de tirets puisque le tirage n'a pas de tirets
nbLettres-=nbTirets;
//Si le mot a trop de lettres, on passe au suivant puisque il ne peut pas etre solution
if (nbLettres > TAILLE_TIRAGE )
continue;
//On cree un tableau qui permet d'indiquer si chacune des lettres du tirage est utilisee
bool utilisee[TAILLE_TIRAGE]={false};
//On commence par supposer que l'on peut ecrire le mot a partir du tirage
bool motvalide=true;
//On parcourt les lettres du mot
for ( unsigned int i=0; i<mot.size(); i++ )
{
//Si c'est un tiret on saute a la lettre suivante puisqu'on a pas de tiret dans le tirage
if(mot[i] == '-')
continue;
//On commence par supposer que la lettre du mot n'est PAS dans le tirage
bool lettrevalide=false;
//On parcourt les lettres du tirage
for (unsigned int j=0; j<tirage.size(); ++j )
{
//Si la lettre du tirage correspond a la lettre du mot ET qu'on a pas encore utilise cette lettre du tirage
if ( mot[i]==tirage[j] && utilisee[j]==false )
{
//On montre que la lettre a ete utilisee
utilisee[j]=true;
//Et on valide la lettre
lettrevalide=true;
//On sort de la boucle pour passer a la lettre suivante du mot
break;
}
}
//Si une lettre est non-valide le mot est non valide donc on passe au mot suivant
if ( !lettrevalide )
{
motvalide=false;
break;
}
}
//Si le mot est valide
if (motvalide)
{
//Si on a un mot avec le meme nombre de lettres
if (nbLettres == motLePlusLong)
{
solution.push_back(mot); //On le stocke
}
else if (nbLettres > motLePlusLong) //Si le mot a plus de lettres
{
solution.clear(); //On vide le tableau
solution.push_back(mot); //Et on met notre nouveau mot
motLePlusLong = mot.size(); //On prend la taille du mot comme taille de reference
}
//Si il a moins de lettres, il nous interesse pas donc on le stocke pas
}
}
//On renvoit le tableau de mots
return solution;
}
int main()
{
//Initialisation du hasard
srand(time(0));
//Creation d'un tirage
string tirage = creerTirage();
cout << endl << "Tirage complet: " << tirage << "\n" << endl;
//Recherche de solution a partir du tirage
Tableau solution(chercher(tirage));
//Si on a pas trouve de solution
if (solution.empty())
{
cout << "Aucune solution trouvee pour ce tirage" << endl;
}
else
{
//Affichage du nombre de lettres de la solution
cout << solution.size() << " solutions possible en " << solution[0].size() << " lettres: " << endl;
//Affichage des solutions
for (unsigned int i(0) ; i<solution.size();++i)
{
cout << i+1 << ") " << solution[i] << endl;
}
}
return 0;
}
Merci à tous ceux qui ont participé et bonne chance avec l'exercice suivant !