R1.01 – Prog#7 – Exercice 9

Un nombre réel peut être représenté sous deux formes dites virgule fixe ou notation scientifique (ou virgule flottante).

  1. un nombre en virgule fixe est composé d’au maximum quatre parties contiguës (sans espace ou séparateur quelconque) :
    1. son signe : ‘+’ ou ‘-‘. S’il est absent, le nombre est considéré comme positif.
    2. sa partie entière, toujours exprimée en base 10,
    3. le caractère point décimal ‘.’ car nous sommes dans le système anglo-saxon !
    4. sa partie décimale, elle aussi toujours exprimée en base 10,

    Si le point décimal est présent, il doit obligatoirement être précédé ou suivi d’au moins un digit décimal.

  2. un nombre en notation scientifique est composé de trois parties obligatoires :
    1. un nombre réel en virgule fixe, exprimé en base 10, signé ou non,
    2. le caractère ‘e’ ou ‘E’,
    3. un nombre entier exprimé en base 10, signé ou non, qui représente la puissance de 10 par laquelle il faut multiplier la première partie pour obtenir la valeur réelle.

      De plus, pour que la chaîne représentant un nombre réel soit valide, il faut que la valeur soit compatible avec le type correspondant (float ou double).

Ecrire la fonction extractionsReels() qui, dans une boucle, extrait (opérateur >>) au clavier (ou sur un fichier redirigé sur l’entrée standard cin) tous les réels et les affiche à l’écran à raison d’un par ligne. La boucle se termine lorsque l’extraction échoue (fail()).

Faire plusieurs essais, en saisissant un ou plusieurs réels par ligne, séparés ou non par des caractères d’espacement, en saisissant des lignes vierges ou seulement composées de caractères d’espacement.

Vous devez constater que :

  1. n’importe quel réel valide est extrait,
  2. tous les caractères d’espacement sont ignorés,
  3. le programme se termine au premier échec d’extraction (voir les indications ci-dessus). Le caractère “fin-de-fichier” (Ctrl+D) permet aussi de terminer la saisie.

Les réels suivants sont valides :

123
123.45
-12e12
-12.e-12
+12.23
-.23
1234567890

La dernière valeur est valide mais tronquée : 1.23457e+09.

Les réels suivants sont invalides et terminent le programme :

-.e12
1e123456789
-e12

R1.01 – Prog#7 – Corrigé

#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
void Flux_cin()
{
string Ligne;
while (true)
{
getline (cin, Ligne);
if (cin.eof()) break;
cout << Ligne << endl;

}
}

void AffichFich()
{
ifstream ifs ("LaFontaine.txt");
string Ligne;
while (true)
{
getline (ifs, Ligne);
if (ifs.eof()) break;
cout << Ligne << endl;
}
}

void NomFichAuClavier()
{
ifstream ifs;
ofstream ofs;

string FichierSource, FichierDestination;
getline (cin, FichierSource);
ifs.open(FichierSource);
getline (cin, FichierDestination);
ofs.open(FichierDestination);
string Ligne;
unsigned Cpt (1);
while (true)
{
getline (ifs, Ligne);
if (ifs.eof()) break;
ofs << Cpt++ << " " << Ligne << endl;
}
}

void ValidFichier()
{
ifstream ifs;
ofstream ofs;

string FichierSource, FichierDestination;

unsigned NbVies (0);
while (true)
{
getline (cin, FichierSource);
ifs.open(FichierSource);
if (ifs.is_open()) break;
++NbVies;
cout << "Gros boulet" << endl;
if (3 == NbVies)
{
cout << "3 echecs d'ouverture de fichier en lecture" << endl;
return;
}
}

NbVies = 0;
while (true)
{
getline (cin, FichierDestination);
ofs.open(FichierDestination);
if (ofs.is_open()) break;
++NbVies;
cout << "Gros boulet" << endl;
if (3 == NbVies)
{
cout << "3 echecs d'ouverture de fichier en ecriture" << endl;
return;
}
}

string Ligne;
unsigned Cpt (1);
while (true)
{
getline (ifs, Ligne);
if (ifs.eof()) break;
ofs << Cpt++ << " " << Ligne << endl;
}
}

void FonctionGet()
{
ifstream ifs;

string FichierSource;
getline (cin, FichierSource);
ifs.open(FichierSource);
char car;

while (true)
{
car = char (ifs.get());
if (ifs.eof()) break;
cout << car /*<< endl*/;
}
}

void  ExtractionsMots()
{
string mot;
while (cin >> mot)
cout << mot << endl;
}

void ExtractionsCars()
{
char Car;
while (cin >> Car)
cout << Car /*<< endl*/;
}

void ExtractionsEntiers()
{
int Entier;
while (cin >> Entier)
cout << Entier << endl;
}

void ExtractionsReels()
{
float Reel;
while (cin >> Reel)
cout << Reel << endl;
}

int main()
{
//cout << "Hello World!" << endl;
//Flux_cin();
//AffichFich();
//NomFichAuClavier();
ValidFichier();
//FonctionGet ();
//ExtractionsMots ();
//ExtractionsCars();
//ExtractionsEntiers ();
//ExtractionsReels ();
return 0;
}

R1.01 – Prog#9 – Exercice 1

Ecrivez la procédure triSelection () de signature

void triSelection (vector<unsigned> & vUint);

Cette procédure trie le vecteur en paramètre selon la méthode du tri par sélection / échange (cf. R1.01 – Algo8 – eox2).

Afin d’initialiser votre vecteur, ajouter ces lignes dans le main () :

#include <cstdlib>
#include <ctime>
...
srand (time(NULL));
vector<unsigned> vUInt (XXX);

for (auto & val : vUInt)
     val = rand () % (vUInt.size() * 10);

Pour finir, écrivez la fonction testVecteurTrie () de signature

void testVecteurTrie (const vector<unsigned> & vUint);

Cette fonction doit tester si le vecteur qui lui est passé en paramètre est trié. Cette vérification doit de faire à l’aide de la fonction assert ().

NB : pensez à mettre un message à la fin de votre fonction testVecteurTrie () pour vous assurer que vous passez tous les tests.

R1.01 – Prog#9 – Exercice 5

Insérer dans le code suivant vos algorithmes de tri.
Modifier le .pro en ajoutant la ligne LIBS += -pthread

Puis faite divers tests en faisant varier les paramètres d’entrée :

  1. la taille des vecteurs;
  2. le nombre de vecteurs différents;
  3. nombre d’itérations par vecteur;
#include <iostream>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <thread>
#include <cassert>

using namespace std;
typedef vector <vector<double>> CMatrix;

CMatrix Mat;

void selectSort (vector <unsigned> & tab){
    //TODO
}

void insertSort (vector <unsigned> & vUint)
{
//TODO
}

void bubbleSort (vector <unsigned> & vUint)
{
//TODO
}

void countingSort (vector <unsigned> & vUint)
{
//TODO
}

void languageSort (vector<unsigned> & VUint)
{
    sort (VUint.begin(), VUint.end());
}

void initMat (unsigned NbColumns)
{
    Mat.resize(5, vector <double> (NbColumns));
}

//http://stackoverflow.com/questions/2962785/c-using-clock-to-measure-time-in-multi-threaded-programs
void protoGenericSort(void (*mySort) (vector <unsigned> & vUint), const vector <unsigned> & vUint, unsigned NbFois, unsigned PosMat, unsigned VectNum)
{
    for (unsigned i (0); i < NbFois; ++i)
    {
        vector <unsigned> copyVUint (vUint);
        struct timespec start, finish;
        double elapsed;
        clock_gettime(CLOCK_MONOTONIC, &start);
        mySort (copyVUint);
        clock_gettime(CLOCK_MONOTONIC, &finish);
        elapsed = (finish.tv_sec - start.tv_sec);
        elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
        Mat [PosMat][i + NbFois * VectNum] = elapsed;
    }
}

void traiterResultats (const unsigned & nbElemAEnlever)
{
    for (vector <double> & UneLigne : Mat)
    {
        //tri
        sort (UneLigne.begin(), UneLigne.end());
        //suppresion des éléments non significatifs
        UneLigne = vector <double> (UneLigne.begin() + nbElemAEnlever / 2, UneLigne.end() - nbElemAEnlever / 2 );
        //plus petit temps
        double min (UneLigne[0]);
        //plus grand temps
        double max (UneLigne[UneLigne.size()-1]);
        //temps median
        double med (UneLigne[UneLigne.size()/2]);

        //On assigne les valeurs memorisees aux 3 premières cases
        UneLigne[0] = min;
        UneLigne[1] = med;
        UneLigne [2] = max;
    }
    //Affichage
    cout << setw (20) << "Tri" << setw (10) << "Min" << setw (10) << "Med" << setw (10) << "Max" << endl;
    vector<string> VMetode {"Selection", "Insertion", "Bulles", "comptage", "Langage"};
    for (unsigned i (0); i < VMetode.size(); ++i)
        cout << setw (20) << VMetode[i] << setw (10) << setprecision(6) << Mat[i][0] << setw (10) << setprecision(6) << Mat[i][1] << setw (10) << setprecision(6) << Mat[i][2] << endl;

}

int main(int argc, char *argv[])
{
    if (argc != 4)
    {
        cerr << "boulette !\n utilisation : " << argv [0] << " (1) NbElem par vecteur (2) Nb de vecteurs differents (3) Nb itérations par vecteur" << endl;
        return 1;
    }

    unsigned NbElem (stoul(argv[1]));
    unsigned NbVecteurs (stoul(argv[2]));
    unsigned NbFois (stoul(argv[3]));

    srand (time(NULL));
    vector <unsigned> VUInt (NbElem);
    initMat (NbFois * NbVecteurs);


    for (unsigned i (0); i < NbVecteurs; ++i)
    {
        for (auto & Val : VUInt)
            Val = rand () % (VUInt.size() * 10);

        thread th1 (protoGenericSort, selectSort, VUInt, NbFois, 0, i);
        thread th2 (protoGenericSort, insertSort, VUInt, NbFois, 1, i);
        thread th3 (protoGenericSort, bubbleSort, VUInt, NbFois, 2, i);
        thread th4 (protoGenericSort, countingSort, VUInt, NbFois, 3, i);
        thread th5 (protoGenericSort, languageSort, VUInt, NbFois, 4, i);
        th1.join();
        th2.join();
        th3.join();
        th4.join();
        th5.join();
        cout << i << "fini" << endl;
    }

    cout << "Taille des vecteurs : " << NbElem << "\nNb de vecteurs : " << NbVecteurs << "\nNb iterations par vecteur : " << NbFois << endl;
    //On traite les résultats en supprimant 10% des éléments
    traiterResultats (NbFois * NbVecteurs / 10);
    return 0;
}

R1.01 – Prog#10 – Exercice 1

Mettre de la couleur dans le terminal sous GNU / Linux

Puisque les cours d’IHM (Interface Homme Machine) ne commencent qu’au second semestre, nous allons voir comment nous pouvons spécifier, dans un programme, la couleur des caractères ainsi que celle du fond d’une console, mais aussi effacer son contenu.
Puisque la console est une émulation d’un terminal VT100, toutes les instructions que nous allons lui donner commencent par \033[. Ensuite, une autre séquence d’instruction, concaténée à la première, provoque l’effacement de l’écran, le changement de la couleur de la police ou du fond.

Remarque : les informations évoquées dans cette partie fonctionnent aussi sous Mac OS-X, mais pas sous Windows.

Effacer l’écran

Afin d’effacer l’écran, la seconde séquence est : H\033[2J. En conséquence, la fonction suivante permet d’effacer l’écran :

void clearScreen () {
    cout << "\033[H\033[2J";
}

Copiez la.

Changer la couleur

Afin de changer la couleur, la seconde séquence est : XXm, où m est le code de la couleur souhaitée. Ce code est constitué de 2 chiffres comme le montre le tableau suivant :

Couleur Code associé
0 réinitialise le système de couleur à la valeur par défaut du shell
30 Noir
31 Rouge
32 Vert
33 Jaune
34 Noir
35 Magenta
36 Cyan

 

Copiez le code suivant :

const unsigned KReset   (0);
const unsigned KNoir    (30);
const unsigned KRouge   (31);
const unsigned KVert    (32);
const unsigned KJaune   (33);
const unsigned KBleu    (34);
const unsigned KMAgenta (35);
const unsigned KCyan    (36);
	
void couleur (const unsigned & coul) {
    cout << "\033[" << coul <<"m";
}

Le code suivant :

couleur (KRouge);
cout << "Rouge" << endl;
couleur (KVert);
cout << "Vert" << endl;
couleur (KReset);
cout << "Retour à la normale" << endl;

provoquera l’affichage :
Rouge
Vert
Retour à la normale

Changer le fond

Pour changer le fond, c’est exactement la même séquence d’instructions que pour changer la couleur. La seule différence provient du fait que les couleurs associées voient leur code respectif augmenté de 10.

Pour des informations complémentaires quant à la gestion du terminal (sous GNU / Linux), vous pouvez visiter cette page.

R1.01 – PROG#10 – EXERCICE 2

Gestion de la grille

Le but du projet est de réaliser une version simplifiée du célèbre jeu “voleur / contrebandier” (base du célèbre PacMan). Les règles du jeu sont les suivantes :

  1. Chaque joueur commence à deux coins diamétralement opposés de la grille. Dans notre cas, le Joueur1 débute en haut à droite et le Joueur2 en bas à gauche.
  2. Chaque joueur joue à tour de rôle, et ne peut faire qu’un unique déplacement, et d’une seule case. Les touches valides de déplacement sont ‘A’ (haut gauche), ‘Z’ (haut), ‘E’ (haut droit), ‘Q’, ‘D’, ‘W’, ‘X, et ‘C’ (mais elles peuvent être changées).
  3. Le jeu s’arrête soit :
    • lorsqu’un joueur atteint la même position dans la grille qu’un autre;
    • lorsqu’un nombre pré-déterminé de coups a été joué. Dans ce cas, il y a match nul.

La grille est représentée par une matrice de taille MxN. Dans les paragraphes suivants, nous considérons que la matrice est carrée.
En conséquence, nous pouvons définir les alias suivants :

typedef vector <char> CVLine; // un type représentant une ligne de la grille
typedef vector <CVLine> CMatrix; // un type représentant la grille
typedef pair   <unsigned, unsigned> CPosition; // un type représentant une coordonnée dans la grille

De plus, les constantes globales (i.e. visibles par toutes les fonctions) suivantes sont définies :

const char kTokenPlayer1 = 'X';
const char kTokenPlayer2 = 'O';
const char kEmpty        = ' ';

Par souci d’uniformité, pour ce TP, le caractère :

  1. 'X' symbolise le pion du joueur 1 (la couleur est à votre guise);
  2. '0' désigne le pion du joueur 2 (la couleur est à votre guise);
  3. ' ' matérialise une case vide.

Affichage de la grille

Travail à effectuer : écrivez le corps de la fonction ShowMatrix () de signature :

void  showMatrix (const CMatrix & Mat);

Cette fonction doit :

  1. faire appel à la fonction clearScreen ();
  2. remettre la couleur des caractères à sa valeur par défaut;
  3. afficher case / case le contenu de la case courante. Si la case n’est pas occupé par un joueur, on affiche une case vide, sinon, on affiche la couleur du joueur (définie auparavant) suivie du jeton.

R1.01 – PROG#10 – EXERCICE 3

Le jeu

Initialisation de la grille

Ecrire la fonction initMat () de signature :

void initMat (CMatrix & Mat, unsigned nbLine, unsigned nbColumn, CPosition & posPlayer1, CPosition & posPlayer2)

Cette fonction a pour but d’initialiser toutes les cases de la grille avec le caractère ' ' ainsi que de mettre le jeton du Joueur1 en haut à droite et celui du Joueur2 en bas à gauche.

Placement d’un jeton au bon endroit

Ecrire la fonction moveToken () de signature :

void moveToken (CMatrix & Mat, char move, CPosition  & pos)

Cette fonction déplace, dans la grille, le jeton situé initialement à la position pos en fonction de la valeur du caractère move, puis met à jour la position.

Cette fonction place le jeton 'X' s’il s’agit du premier joueur (ou 'O' s’il s’agit du second, selon la valeur du caractère move)
au bon endroit (indiqué par pos) dans la matrice représentant la grille. La position pos est aussi changée.

L’algorithme principal

Le but de cette partie est d’écrire la fonction ppal () (fonction qui nous sert de programme principal) qui gère la partie. Cette fonction a pour signature :

int ppal ()

Dans le main (), vous devez uniquement appeler cette fonction. Cette fonction :

  1. initialise la matrice (grille) du jeu ainsi que le nombre de coup maximal;
  2. affiche la grille;
  3. entre dans une boucle tant qu’on peut jouer et qu’il n’y a pas de victoire;
    1. saisit le caractère correspondant à un déplacement;
    2. place le pion au bon endroit.
      Attention, aucun contrôle quant à la possibilité d’effectuer le déplacement de la grille n’est effectué.
    3. affiche la grille;
    4. effectue le test ;
  4. teste dans quel(s) état(s) on est sorti de boucle (s’il y a eu une victoire ou un match nul) et affiche les informations en conséquence.

Précision sur l’instruction “tant qu’on peut jouer” et conséquences

Puisque la grille contient M*M cases, il arrive fréquemment qu’aucun des joueurs ne prenne le dessus sur son adversaire. En conséquence, il faut limiter le nombre de mouvements des 2 joueurs.