Nom : CRYPTO 1: Chiffre de César Sujet : chaînes de caractères, algo
Introduction générale
L'utilisation du ROT13 dans certains des posts précédents, m'a donné envie de débuter une série d'exercices sur la cryptologie. Nous allons explorer quelques méthodes de cryptage de données dans les exercices qui vont suivre par ordre croissant de difficulté.
Pour chaque algorithme de cryptage, il y aura plusieurs parties afin de représenter les différentes disciplines de la cryptologie.
1) La partie cryptographie qui consiste à chiffrer et déchiffrer un message avec l'aide ou non d'une clé.
2) La partie cryptanalyse qui consiste à "casser" le code et donc à découvrir un message secret sans connaître la clé.
La partie 2 étant plus difficile que la partie 1.
Introduction de l'exercice du mois
Le premier algorithme que nous allons étudier, est le chiffre de César ou si on prend le cas général, le chiffrement par décalage.
L'algorithme consiste à décaler les lettres d'un message d'un certain nombre de position dans l'alphabet. Par exemple pour un décalage de 1, le texte:
SITE DU ZERO
devient:
TJUF EV AFSP
Le décryptage se fait de la même manière en utilisant le décalage opposé.
On ne considère que des messages sans accents.
Votre programme
Niveau 1
Vous devez fournir un programme permettant de crypter un message en laissant la liberté à l'utilisateur de choisir le décalage qu'il désire utiliser.
Ce programme devra aussi permettre de décrypter les message reçus.
Vous pouvez aussi donner la possibilité de crypter (et décrypter) entièrement un fichier.
Niveau 2
Votre but cette fois, est de "casser" le code sans connaître le décalage qui a été utilisé.
1) La partie cryptanalyse qui consiste à chiffrer et déchiffrer un message avec l'aide ou non d'une clé.
2) La partie cryptologie qui consiste à "casser" le code et donc à découvrir un message secret sans connaître la clé.
Ce serait pas le contraire : la cryptologie consiste à chiffrer/déchiffrer et la cryptanalyse à casser un cryptage ?
Sinon c'est une bonne idée de sujet(s), je compte participer .
Pour la cryptanalyse, on peut considérer que les 3 lettres les plus utilisées sont le e, le a et le i et ensuite les déterminer en utilisant le décalage entre les 3 caractères obtenus ?
Bonjour tout le monde ! Il est temps que je dévoile une solution pour l'exercice du mois d'octobre. Vous avez été 22 à m'envoyer une solution.
Il y avait beaucoup de bonnes choses dans les codes reçus. Cependant, je n'ai vu personne qui avait implémenté les opérateurs et les constructeurs correctement. C'était toujours soit l'un soit l'autre. Voici donc ma solution.
La base de la classe
Nous devons réaliser une classe représentant la notion de fraction. Elle aura donc naturellement deux attributs, deux nombres entiers qui représenteront le numérateur et le dénominateur de la fraction.
Et là on peut se poser la première question : "Public ou privé ?" Habituellement, les attributs d'une classe devraient être privés, mais dans notre cas, nous voulons donner l'accès aux attributs de la classe à l'utilisateur.
On a alors deux possibilités:
1) Mettre des fonctions "get()" et "set()" pour nos attributs.
2) Mettre les attributs en public.
La solution 1 permet d'avoir un contrôle sur ce que l'utilisateur fait (par exemple empêcher un dénominateur nul), mais est légèrement plus lourd à programmer. La solution 2 donne un accès sans contrôle à l'utilisateur, mais on peut supposer qu'un utilisateur sensé saura que le dénominateur d'une fonction ne doit pas être nul.
J'ai choisi ici la solution 1, afin de vous montrer un cas concret d'utilisation des exceptions, mais la 2 me semble tout à fait applicable dans ce contexte. A ce stade, nous avons donc:
class Fraction
{
private:
int numerateur;
int denominateur;
};
Pour ce qui est du signe, j'ai décidé d'utiliser la convention que le dénominateur est toujours positif et que seul le numérateur porte le signe.
Les constructeurs simples
Pour notre classe, il nous faut un ou plusieurs constructeurs. J'avais demandé l'écriture d'un constructeur à partir d'un entier et d'un constructeur à partir d'un couple d'entier.
Si l'on se souvient que <math>\(3 = \frac{3}{1}\)</math>, on peut gagner du temps en écrivant qu'un seul constructeur avec un second argument possédant une valeur par défaut. On peut même aller plus loin et proposer un constructeur entièrement par défaut en mettant une valeur pour le premier argument. Ainsi on a un constructeur par défaut qui crée une fraction valant zéro.
Fraction(int numerateur=0,int denominateur=1)
Dans le corps, il faut faire trois vérifications.
1) Vérifier que le dénominateur est non-nul.
2) Simplifier la fraction si possible.
3) Gérer le signe si l'utilisateur essaye de faire une fraction <math>\(\frac{5}{-3}\)</math> par exemple.
Pour les points 2, nous allons créer des fonctions dédiées puisque les simplifications seront aussi utiles pour les opérateurs. Nous avons donc le code suivant dans notre ".cpp" :
#include <stdexcept> //Pour les exceptions
Fraction::Fraction(int n,int d)
:numerateur(std::abs(n)), //On stocke la valeur absolue puisque on veut gerer nous-meme le signe
denominateur(std::abs(d))
{
//Le denominateur nul est interdit on lance une exception si ca arrive
if (d==0) throw std::runtime_error("Fraction: Denominateur nul");
//Si il y a un signe, il va au numerateur
if (n*d < 0)
numerateur = -numerateur;
//Et on simplifie la fraction si possible
simplifie();
}
std::runtime_error est un type d'exception défini dans la bibliothèque standard que l'on utilise pour spécifier les erreurs se produidant lors de l'exécution.
Et le constructeur de copie ?
On en a pas besoin vu que notre classe ne contient pas de pointeur et qu'il n'y a aucune opération "spéciale" à réaliser lors d'une copie. Le constructeur de copie généré par le compilateur sera suffisant.
Les autres constructeurs seront détaillés plus loin.
Simplifier une fraction
Une fraction est simplifiable si son numérateur et son dénominateur ont un pgdc (plus grand diviseur commun) différent de 1. Il nous faut donc une fonction qui calcule le pgdc. Cette fonction n'est pas spécifique à la classe, elle n'a donc rien à faire dans la classe; elle "vit" à côté. On utilise simplement l'algorithme usuel.
int pgcd(int a,int b)
{
while (b!=0)
{
const int temp = b;
b = a % b; //On cherche le reste de la division de a par b tant que b est different de 0
a = temp;
}
return a;
}
On peut maintenant mettre notre fonction de simplication dans notre classe. Cette fonction va dans la partie privée, puisque l'utilisateur n'a pas à l'appeler directement.
void Fraction::simplifie()
{
//Calcul du pgdc du numerateur et du denominateur
const int diviseur = pgcd(std::abs(numerateur),denominateur);
//Si on peut simplifier la fraction, alors on simplifie
if (diviseur != 1)
{
numerateur /= diviseur;
denominateur /= diviseur;
}
}
Pour ce qui est de la gestion du signe, on a également une fonction privée qui va mettre le signe au numérateur si nécessaire.
void Fraction::signe()
{
if (numerateur * denominateur >= 0) //Si le numerateur et le denominateur sont positifs ou négatifs
{ //Alors la fraction est positive
numerateur = std::abs(numerateur);
denominateur = std::abs(denominateur);
}
else
{ //Sinon, elle est negative
numerateur = -std::abs(numerateur);
denominateur = std::abs(denominateur);
}
}
On ne peut pas utiliser cette fonction dans le constructeur puisque, on stocke les valeurs absolues dans un premier temps.
Les accesseurs
Il nous faut deux fonctions permettant d'accéder au numérateur et au dénominateur. Ces fonctions sont spécifiées "const" puisqu'elles ne modifient pas la fraction.
int getNumerateur() const;
int getDenominateur() const;
L'opérateur d'affichage
La signature de l'opérateur d'affichage est toujours:
Cette fonction est toujours en-dehors de la classe.
L'affichage doit se faire sout la forme "numerateur" / "denominateur" sauf si le denominateur vaut 1, auquel cas on affiche que le numérateur. Cela nous donne donc:
std::ostream& operator<<(std::ostream& flux,const Fraction& f)
{
//On affiche le numerateur
flux << f.getNumerateur();
//Et le numerateur si il ne vaut pas 1
if (f.getDenominateur() != 1)
flux << "/" << f.getDenominateur();
return flux;
}
Fonction toDouble()
La fonction permettant de convertir une fraction en un nombre à virgule est très simple, puisqu'il suffit de diviser le numérateur par le dénominateur pour obtenir le nombre souhaité.
double Fraction::toDouble() const
{
//Division du numerateur par le denominateur
return static_cast<double>(numerateur)/denominateur;
}
Remarquez à nouveau le "const" et le fait qu'on utilise "static_cast<double>" en C++ pour transformer un nombre entier en nombre à virgule.
Opérateurs de comparaison
Où mettre ces opérateurs ? Dans la classe ou en-dehors ? Les deux sont possibles, mais mettre les opérateurs prenant deux opérandes en-dehors de la classe est souvent (j'aurais aimé mettre toujours ) mieux. En effet, vu que nous avons des constructeurs int -> Fraction et double -> Fraction, notre opérateur déclaré à l'extérieur permettera également de faire des tests du type <math>\(2.5 == \frac{5}{2}\)</math> qui ne seraient pas possible si l'on avait défini l'opérateur à l'intérieur de la classe. En effet, dans ce cas l'opérande de gauche doit toujours être l'objet, ce qui n'est pas le cas dans l'exemple que je vous ai fourni.
La bonne manière de réaliser cela est de mettre les opérateurs +=,-=,... dans la classe et les opérateurs +,-,... en-dehors pour les mêmes raisons que précédemment. On a donc le code suivant pour l'opérateur += :
Vous remarquerez le type de retour ainsi que le fait que l'on passe l'argument par référence constante.
Avec cela, on peut écrire l'opérateur +, ce qui donne :
Les autres opérateurs fonctionnent de la même manière à partir des règles que vous avez appris à l'école.
Pour le ^=, on va juste multiplier la fraction par elle-même un certain nombre de fois.
Fraction& Fraction::operator^=(int n)
{
//Les valeurs a multiplier
const int num = numerateur;
const int den = denominateur;
numerateur = 1;
denominateur = 1;
//On multiplie par la fraction n fois
for (int i(0);i < std::abs(n); ++i)
{
numerateur *= num;
denominateur *= den;
}
//Si la puissance etait negative, on inverse la fraction
if (n < 0)
std::swap(numerateur,denominateur);
//On gere le signe
signe();
//On simplifie la fraction
simplifie();
return *this;
}
Autres opérateurs
On peut également écrire d'autres opérateurs comme par exemple le moins unitaires (celui qui permet d'écrire -a). C'est également une fonction externe à la classe:
Une bonne solution consiste à utiliser les stringstream pour extraire les nombres depuis la chaine de caractère.
Fraction::Fraction(const std::string& x)
:numerateur(0),
denominateur(1)
{
//On declare un flux depuis une chaine pour lire les chiffres
std::istringstream flux(x);
char symbole; //Pour la lecture du /
//On lit le numerateur
flux >> numerateur;
//On lit le /
flux >> symbole;
//On lit le denominateur
flux >> denominateur;
//Le denominateur nul est interdit on lance une exception si ca arrive
if (denominateur==0) throw std::runtime_error("Fraction: Denominateur nul");
//On gere le cas special du signe
signe();
//Et on simplifie la fraction si possible
simplifie();
}
Cette version n'est pas sécurisée et suppose que l'utilisateur entre correctement les informations.
Construction depuis un double
Voici la version de Gymnopaul de ce constructeur. C'est la meilleure version que j'ai reçue et elle est plus simple que la mienne :
#include <cmath>
Fraction::Fraction(double nombre)
:numerateur(0),
denominateur(1)
{
// On crée une chaîne pour le nombre
std::string chaine;
std::ostringstream oss;
oss << nombre;
chaine = oss.str();
//On cherche la virgule et le nombre de ceimales
bool pointTrouve = false;
int nombredeDecimaux = 0;
// On parcourt la chaîne
for(size_t i=0; i<chaine.size(); i++)
{
// Si le point a été trouvé, le caractère chaine[i] est compris dans la partie décimale
if(pointTrouve)
nombredeDecimaux++;
/* Si le caractère chaine[i] n'est pas un nombre, c'est le point
et alors on peut compter les décimales */
if(chaine[i] == '.')
pointTrouve = true;
}
/* Grâce aux nombres de la partie décimale, on
multiplie le nombre décimal en paramètre
par une puissance de 10 du nombre de décimaux
Cela donne le numérateur, et le dénominateur
est la puissance de 10
ex : pour le nombre 2.267 en paramètre,
il y a 3 décimaux : 2, 6 et 7.
On multiplie donc par 10^3 soit 1000,
ce qui donne comme numérateur 2267
et comme dénominateur 1000 */
numerateur = static_cast<int>(nombre * std::pow(10., nombredeDecimaux));
denominateur = static_cast<int>(std::pow(10., nombredeDecimaux));
//On gere le signe
signe();
//et on simplifie
simplifie();
}
Code complet
Voici un le code complet de la classe avec quelques trucs en plus.
Fraction.hpp:
#ifndef FRACTION_HPP
#define FRACTION_HPP
#include <string>
#include <ostream>
class Fraction
{
public:
//Constructeurs
Fraction(int n=0,int d=1);
Fraction(double x);
Fraction(const std::string& x);
//Accesseurs
int getNumerateur() const;
int getDenominateur() const;
//Operateurs mathematiques
Fraction& operator+=(const Fraction& f);
Fraction& operator-=(const Fraction& f);
Fraction& operator*=(const Fraction& f);
Fraction& operator/=(const Fraction& f);
Fraction& operator^=(int n);
//Incrementation
Fraction& operator++();
Fraction& operator--();
Fraction operator++(int); //Voir FAQ de developpez.com pour la difference
Fraction operator--(int);
//Fonctions membres
double toDouble() const;
private:
//Attributs
int numerateur;
int denominateur;
//Fonctions utilitaires
void simplifie(); //Simplifie la fraction si possible
void signe(); //Met le signe uniquement au numerateur
};
//Operateurs de comparaisons
bool operator==(const Fraction& f,const Fraction& g);
bool operator!=(const Fraction& f,const Fraction& g);
bool operator<=(const Fraction& f,const Fraction& g);
bool operator>=(const Fraction& f,const Fraction& g);
bool operator<(const Fraction& f,const Fraction& g);
bool operator>(const Fraction& f,const Fraction& g);
//Test de nullite
bool operator!(const Fraction& f); //Renvoit true si la fraction est nulle
//Operateurs mathématiques unitaires
Fraction operator-(const Fraction& f);
Fraction operator+(const Fraction& f);
//Operateurs mathématiques binaires
Fraction operator+(const Fraction& f,const Fraction& g);
Fraction operator-(const Fraction& f,const Fraction& g);
Fraction operator*(const Fraction& f,const Fraction& g);
Fraction operator/(const Fraction& f,const Fraction& g);
Fraction operator^(const Fraction& f,int n);
//Affichage dans un flux
std::ostream& operator<<(std::ostream&,const Fraction&);
//Valeur absolue
Fraction abs(const Fraction& f);
//Fonction mathématique utile
int pgcd(int a,int b);
#endif //FRACTION_HPP
Fraction.cpp:
#include "Fraction.hpp"
#include <stdexcept>
#include <sstream>
#include <cmath>
// FONCTIONS MATHEMATIQUE UTILE ------------------------------------------------------------
int pgcd(int a,int b)
{
while (b!=0)
{
const int temp = b;
b = a % b; //On cherche le reste de la division de a par b tant que b est different de 0
a = temp;
}
return a;
}
// CONSTRUCTEURS ----------------------------------------------------------------------------
Fraction::Fraction(int n,int d)
:numerateur(std::abs(n)),
denominateur(std::abs(d))
{
//Le denominateur nul est interdit on lance une exception si ca arrive
if (d==0) throw std::runtime_error("Fraction: Denominateur nul");
//Si il y a un signe, il va au numerateur
if (n*d < 0)
numerateur = -numerateur;
//Et on simplifie la fraction si possible
simplifie();
}
Fraction::Fraction(const std::string& x)
:numerateur(0),
denominateur(1)
{
//On declare un flux depuis une chaine pour lire les chiffres
std::istringstream flux(x);
char symbole; //Pour la lecture du /
//On lit le numerateur
flux >> numerateur;
//On lit le /
flux >> symbole;
//On lit le denominateur
flux >> denominateur;
//Le denominateur nul est interdit on lance une exception si ca arrive
if (denominateur==0) throw std::runtime_error("Fraction: Denominateur nul");
//On gere le cas special du signe
signe();
//Et on simplifie la fraction si possible
simplifie();
}
Fraction::Fraction(double nombre)
:numerateur(0),
denominateur(1)
{
// On crée une chaîne pour le nombre
std::string chaine;
std::ostringstream oss;
oss << nombre;
chaine = oss.str();
//On cherche la virgule et le nombre de ceimales
bool pointTrouve = false;
int nombredeDecimaux = 0;
// On parcourt la chaîne
for(size_t i=0; i<chaine.size(); i++)
{
// Si le point a été trouvé, le caractère chaine[i] est compris dans la partie décimale
if(pointTrouve)
nombredeDecimaux++;
/* Si le caractère chaine[i] n'est pas un nombre, c'est le point
et alors on peut compter les décimales */
if(chaine[i] == '.')
pointTrouve = true;
}
/* Grâce aux nombres de la partie décimale, on
multiplie le nombre décimal en paramètre
par une puissance de 10 du nombre de décimaux
Cela donne le numérateur, et le dénominateur
est la puissance de 10
ex : pour le nombre 2.267 en paramètre,
il y a 3 décimaux : 2, 6 et 7.
On multiplie donc par 10^3 soit 1000,
ce qui donne comme numérateur 2267
et comme dénominateur 1000 */
numerateur = static_cast<int>(nombre * std::pow(10., nombredeDecimaux));
denominateur = static_cast<int>(std::pow(10., nombredeDecimaux));
//On gere le signe
signe();
//et on simplifie
simplifie();
}
//ACCESSEURS -----------------------------------------------------------------------------------
int Fraction::getNumerateur() const
{
return numerateur;
}
int Fraction::getDenominateur() const
{
return denominateur;
}
// FONCTIONS UTILITAIRES -----------------------------------------------------------------------
void Fraction::simplifie()
{
//Calcul du pgdc du numerateur et du denominateur
const int diviseur = pgcd(std::abs(numerateur),denominateur);
//Si on peut simplifier la fraction, alors on simplifie
if (diviseur != 1)
{
numerateur /= diviseur;
denominateur /= diviseur;
}
}
void Fraction::signe()
{
if (numerateur * denominateur >= 0) //Si le numerateur et le denominateur sont positifs ou négatifs
{ //Alors la fraction est positive
numerateur = std::abs(numerateur);
denominateur = std::abs(denominateur);
}
else
{ //Sinon, elle est negative
numerateur = -std::abs(numerateur);
denominateur = std::abs(denominateur);
}
}
// OPERATEURS MATHEMATIQUES -------------------------------------------------------------------
Fraction& Fraction::operator+=(const Fraction& f)
{
//On calcule la somme
numerateur = numerateur * f.denominateur + f.numerateur * denominateur;
denominateur *= f.denominateur;
//Et on simplifie
simplifie();
return *this;
}
Fraction& Fraction::operator-=(const Fraction& f)
{
//On calcule la difference
numerateur = numerateur * f.denominateur - f.numerateur * denominateur;
denominateur *= f.denominateur;
//Et on simplifie
simplifie();
return *this;
}
Fraction& Fraction::operator*=(const Fraction& f)
{
//On calcule le produit
numerateur *= f.numerateur;
denominateur *= f.denominateur;
//Et on simplifie
simplifie();
return *this;
}
Fraction& Fraction::operator/=(const Fraction& f)
{
//On calcule le produit
numerateur *= f.denominateur;
denominateur *= f.numerateur;
//On gere le cas special du signe
signe();
//Et on simplifie
simplifie();
return *this;
}
Fraction& Fraction::operator^=(int n)
{
const int num = numerateur;
const int den = denominateur;
numerateur = 1;
denominateur = 1;
//Cas general, on multiplie par la fraction n fois
for (int i(0);i < std::abs(n); ++i)
{
numerateur *= num;
denominateur *= den;
}
//Si la puissance etait negative, on inverse la fraction
if (n < 0)
std::swap(numerateur,denominateur);
//On gere le signe
signe();
//On simplifie la fraction
simplifie();
return *this;
}
// FONCTION MEMBRE ------------------------------------------------------------------------------
Fraction& Fraction::operator++()
{
return *this += 1;
}
Fraction& Fraction::operator--()
{
return *this -= 1;
}
Fraction Fraction::operator++(int)
{
const Fraction temp(*this);
*this += 1;
return temp;
}
Fraction Fraction::operator--(int)
{
const Fraction temp(*this);
*this -= 1;
return temp;
}
// FONCTION MEMBRE ------------------------------------------------------------------------------
double Fraction::toDouble() const
{
//Division du numerateur par le denominateur
return static_cast<double>(numerateur)/denominateur;
}
// AFFICHAGE DANS UN FLUX -----------------------------------------------------------------------
std::ostream& operator<<(std::ostream& flux,const Fraction& f)
{
//On affiche le numerateur
flux << f.getNumerateur();
//Et le numerateur si il ne vaut pas 1
if (f.getDenominateur() != 1)
flux << "/" << f.getDenominateur();
return flux;
}
// OPERATEURS DE COMPARAISON -------------------------------------------------------------------
bool operator==(const Fraction& f,const Fraction& g)
{
return f.getNumerateur() == g.getNumerateur() && f.getDenominateur() == g.getDenominateur();
}
bool operator!=(const Fraction& f,const Fraction& g)
{
return !(f == g);
}
bool operator<=(const Fraction& f,const Fraction& g)
{
return f.toDouble() <= g.toDouble();
}
bool operator>=(const Fraction& f,const Fraction& g)
{
return g.toDouble() <= f.toDouble();
}
bool operator<(const Fraction& f,const Fraction& g)
{
return !(f>=g);
}
bool operator>(const Fraction& f,const Fraction& g)
{
return !(f<=g);
}
// TEST DENULLITE ------------------------------------------------------------------------------
bool operator!(const Fraction& f)
{
return f.getNumerateur() == 0;
}
// OPERATEURS MATHEMATIQUES UNITAIRES ----------------------------------------------------------
Fraction operator-(const Fraction& f)
{
return Fraction(-f.getNumerateur(),f.getDenominateur());
}
Fraction operator+(const Fraction& f)
{
return Fraction(+f.getNumerateur(),f.getDenominateur());
}
// OPERATEURS MATHEMATIQUES BINAIRES -----------------------------------------------------------
Fraction operator+(const Fraction& f,const Fraction& g)
{
return Fraction(f)+=g;
}
Fraction operator-(const Fraction& f,const Fraction& g)
{
return Fraction(f)-=g;
}
Fraction operator*(const Fraction& f,const Fraction& g)
{
return Fraction(f)*=g;
}
Fraction operator/(const Fraction& f,const Fraction& g)
{
return Fraction(f)/=g;
}
Fraction operator^(const Fraction& f,int n)
{
return Fraction(f)^=n;
}
// VALEUR ABSOLUE -------------------------------------------------------------------------------
Fraction abs(const Fraction& f)
{
return Fraction(std::abs(f.getNumerateur()),f.getDenominateur());
}
Si vous avez des questions, n'hésitez pas à les poser, je donnerai plus de détails. Une version "professionelle" et optimisée de cette classe se trouve dans boost.
Wooow ma version du constructeur en double exposée au yeux de tous !
Comme quoi on voit que tes exercices m'ont fait énormément progresser. Encore merci !
Dès que j'ai le temps je fais l'exercice de cryptage !
En fait, j'avais rédigé un truc pas mal plus compliqué mais qui ne fesait intervenir que des opérations mathématiques. Sauf que c'était pas très clair comme manière de faire.
L'avantage de ta méthode c'est qu'elle est explicite, même si je pense qu'on puisse faire plue efficace (c.f. celui de boost), par exemple en remplaçant les pow par autre chose de spécifique pour les puissances de 10. Mais bon, ce n'est pas le but de l'exercice et c'est plus clair comme ça.
C'est la première fois que je post ici et c'est pour montrer un problème que je ne saurai résoudre.
Le programme des chiffres et formidable mais voyez ce que j'ai eu:
10 / 4 est égale à 2,5.
J'aimerai savoir, comment remédier à ça?
Bonne idée cet exo, je vais essayer de m'y mettre =) (c'est le premier exo que je fais, j'avais un peu décroché du C++ à cause de plusieurs projets web)
Il faut faire un code qui se compile sous tous les OS? Pour savoir si je peux utiliser windows.h pour les couleurs de la console
Sympas cet exo, il me motive bien et je pense que sa va etre ma premierre participation
Mais j'ai une petite question : doit t'on décaler les caractère accentué (é,è,ê,ù,à) et donc les considérer comme leurs équivalents non accentué ?(je pense que oui, mais bon).
Bon aller je vais essayer de voir pour le niveau 2 car ça ne ma pas l'air facile(à moins de faire un espèce de brute force demandant à l'utilisateur à chaque essaie si le décryptage est bon (oui, oui je sais c'est pas l'exercice ))
Bon aller je vais essayer de voir pour le niveau 2 car ça ne ma pas l'air facile(à moins de faire un espèce de brute force demandant à l'utilisateur à chaque essaie si le décryptage est bon (oui, oui je sais c'est pas l'exercice ))
Si le texte crypté est suffisamment long, l'analyse fréquentielle donne la bonne réponse dans 100% des cas (pas besoin de force brute).
Sinon Nanoc, tu comptes faire la cryptanalyse du chiffre de Vigenère ensuite ? Ça corserait un peu la difficulté, mais rien d'insurmontable !
Inkamath on GitHub - Interpréteur d'expressions mathématiques. Reprise du développement en cours.
Mais j'ai une petite question : doit t'on décaler les caractère accentué (é,è,ê,ù,à) et donc les considérer comme leurs équivalents non accentué ?(je pense que oui, mais bon).
Les caractères accentués ne font pas partis de la table ASCII de base, donc non, de plus, comment savoir après un décalage de 1 par exemple (é => f) faire le contraire (f => é) ?
Sinon Nanoc, tu comptes faire la cryptanalyse du chiffre de Vigenère ensuite ? Ça corserait un peu la difficulté, mais rien d'insurmontable !
Oui. D'autres méthodes suivront.
Citation : 11
Sympas cet exo, il me motive bien et je pense que sa va etre ma premierre participation
Bienvenue !
Citation : 11
Mais j'ai une petite question : doit t'on décaler les caractère accentué (é,è,ê,ù,à) et donc les considérer comme leurs équivalents non accentué ?(je pense que oui, mais bon).
Non. Les caractères accentués ne sont pas standards et ça poserait trop de problème de les gérer ici.