Cours 7 – Le 1er Projet

Preview:

DESCRIPTION

Cours 7 – Le 1er Projet. Analyse du sujet Types de données nécessaires Opérations requises Solution Spécification Exemple Implémentation. Analyse du sujet – détermination des types. - PowerPoint PPT Presentation

Citation preview

Cours 7 – Le 1er Projet

• Analyse du sujet– Types de données nécessaires– Opérations requises

• Solution– Spécification– Exemple– Implémentation

Analyse du sujet – détermination des types

Le but du jeu consiste à vider une grille de ses billes en moins de coups possible. Initialement, la grille est pleine de billes de différentes couleurs. Pour jouer un coup, le joueur sélectionne une bille de la grille. Toutes les billes voisines ayant la même couleur sont retirées de la grille. Pour être valide, au moins une case voisine doit contenir une bille de même couleur que celle sélectionnée.

La notion de voisinage et la façon dont les billes sont retirées sont explicitées sur l’exemple suivant. Dans la grille la plus à gauche, le joueur sélectionne la bille se trouvant en (c, c). …Le score du joueur après ces deux coups est donc de 32 points.

Types de données

• Données manipulées et types associés– Couleur => un entier (de 0 à NBCOUL-1)

– Bille => sa couleur

– Case => la bille (ou NBCOUL si vide)+ des coordonnées (2 entiers)

– Grille => une matrice de billes

– Coup => des coordonnées

– Score => un entier naturel

– Joueur => non représenté dans le programme

– Partie => une grille + un score

Opérations associées aux données

• L’étude du sujet nous indique– Pour les billes

• Tirage aléatoire d’une couleur

• Des opérations de comparaison (tester que 2 billes ont la même couleur)

– Pour des coordonnées (un coup)• Saisir des coordonnées

– Pour le score• Augmenter le score d’un certain nombre de points

Opérations associées aux données

• L’étude du sujet nous indique– Pour la grille

• Remplissage avec des billes de couleur choisie aléatoirement

• Savoir si un coup est jouable (tester la validité des coordonnées et les billes voisines)

• Retirer les billes correspondant à un coup jouable

– Pour la partie• Savoir si la partie est finie• Jouer un coup jouable• Afficher la partie dans son état actuel

Une solution avec 2 classes – documentation

• 2 classes sont définies– Coord (coord.h) : gère des coordonnées– Marble (marble.h) : gère une partie

• Toutes les pré-conditions sont testées par un appel à la fonction assert

Classe Coord• Gestion de coordonnées (2 entiers)• Méthodes

Coord(int x=0, int y=0);

Rôle : constructeur.

int x() const;

Rôle : renvoie l’ordonnée.

int y() const;

Rôle : renvoie l’abscisse.

Coord operator+(const Coord&) const;

Rôle : renvoie la somme des coordonnées courantes avec celles passées en paramètre.

Classe Coord (suite)

• Fonctions associées

Attention : pour des raisons de simplicité, les opérations d’entrée/sortie sont réalisées sous la forme de caractère. Par exemple, la saisie du couple ‘a’ ‘b’ initialisera l’objet à Coord(0,1) et son affichage produira la chaîne « (a, b) ».

std::ostream& operator<<(std::ostream&, const Coord&);

Rôle : affiche des coordonnées sur le flux de sortie.

std::istream& operator>>(std::istream&, Coord&);

Rôle : saisie des coordonnées à partir du flux d’entrée.

Exemple de programme utilisateur#include <iostream>#include <cassert>using namespace std;#include "coord.h"

const int TAILLE = 5;

bool isIn(const Coord& c) {return c.x() >= 0 && c.x() < TAILLE &&

c.y() >= 0 && c.y() < TAILLE;}

void voisine(const Coord& c) {assert(isIn(c));static const Coord DIR[4] = { Coord(1,0), Coord(-1,0),

Coord(0,1), Coord(0,-1)};

for (int i=0; i<4; i++)if (isIn(c+DIR[i]))

cout << c+DIR[i] << endl;}

Classe Marble• Gestion d’une partie• Méthodes

Marble();

Rôle : constructeur. La grille est remplie aléatoirement de billes et le score est initialisé à zéro.

int tire(const Coord&);

Rôle : joue un coup aux coordonnées passées en paramètre et renvoie le nombre de billes retirées. Les billes voisines et de même couleur sont retirées et le score courant est augmenté en fonction du nombre de ces billes.

Pré-condition : les coordonnées passées en paramètre doivent désigner un coup jouable.

bool jouable(const Coord&) const;

Rôle : renvoie vrai si les coordonnées satisfont la pré-condition de la méthode tire.

bool fini() const;

Rôle : renvoie vrai s’il n’y a plus de coup jouable.

Classe Marble (suite)

void affiche(std::ostream&) const;

Rôle : affiche l’état de la grille et le score courant sur le flux de sortie passé en paramètre.

• Fonctions associées

std::ostream operator<<(std::ostream&, const Marble&);

Rôle : affiche l’état de la grille et le score courant sur le flux de sortie.

Exemple de programme utilisateur#include <iostream>using namespace std;#include "marble.h"

int main() {Marble m;Coord c;cout << m << endl;while (!m.fini()) {

do {cin >> c;

} while (!m.jouable(c));int g = m.tire(c);cout << m << endl;

}return 0;

}

Implémentation (coord.h)

#ifndef _COORD_#define _COORD_class Coord {public:

Coord(int a=0, int b=0): x_(a),y_(b) {};

int x() const {return x_;};

int y() const {return y_;};

Coord operator+(const Coord& c) const {return Coord(x_+c.x_ , y_+c.y_);

};

private:int x_, y_;

};

coord.h (suite)

inline std::ostream& operator<<(std::ostream& o, const Coord& c) {o << '(' << char('a'+c.x()) << ',' << char('a'+c.y()) << ')';return o;

};

inline std::istream& operator>>(std::istream& i, Coord& c) {char x, y;i >> x >> y;c = Coord(x-'a', y-'a');return i;

};

#endif

Implémentation (marble.h)

#ifndef _MARBLE_#define _MARBLE_

#include <iostream>#include "coord.h“

class Marble {public:

Marble();

// renvoie le nb de billes retiréesint tire(const Coord&);

// renvoie si un coup est jouablebool jouable(const Coord&) const;

// renvoie si la partie est finiebool fini() const;

// affiche la partie void affiche(std::ostream&) const;

marble.h (suite)private:

enum {LARGEUR=5, HAUTEUR=5, NB_COULEURS=3};

void retire(const Coord&);

void tombe();

bool vide(int, int) const;

void vider(int, int);

static int ind(int h, int l);

static int ind(const Coord& c);

static bool correct(const Coord& c);

int t[LARGEUR*HAUTEUR];int score;

};

inline std::ostream operator<<(std::ostream& o, const Marble& m) {m.affiche(o);return o;

};

#endif

marble.cpp (extrait)Marble::Marble() {

srand(_getpid());for (int i=0; i<HAUTEUR*LARGEUR; i++)

t[i] = rand()%(NB_COULEURS);score = 0;

}

static const Coord dir[4] = { Coord(-1,0), Coord(1,0), Coord(0,-1), Coord(0,1)};

bool Marble::jouable(const Coord& c) const {if (!correct(c) || vide(c.x(), c.y()))

return false;

int cl = t[ind(c)];bool ok = false;

for (int i=0; !ok && i<4; i++) {Coord v = c + dir[i];if (correct(v) && t[ind(v)]==cl)

return true;}

return false; // un coup doit retirer au moins deux billes !!!}

marble.cpp (suite)int Marble::tire(const Coord& c) {

assert(jouable(c));

int cl = t[ind(c)];list<Coord> nouv;set<Coord> anc;

nouv.push_front(c);while (!nouv.empty()) {

Coord n = nouv.front();nouv.pop_front();anc.insert(n);for(int i=0; i<4; i++) {

Coord v = n + dir[i];if (correct(v) && t[ind(v)]==cl && anc.find(v)==anc.end())

nouv.push_front(v);}

}

for(std::set<Coord>::const_iterator it=anc.begin(); it!=anc.end(); it++) retire(*it);

tombe();

int nb = anc.size();score += (nb/5+1)*nb;

return nb;}

Conclusion• Documentation

– Structuration (prototype, rôle, pré-condition, …)

– Complétude et rigueur

– Clarté et justesse du vocabulaire

• Traitement des erreurs– Complétude et documentation

• Masquage des informations– Structuration des données

(définir des types)

– Accesseurs

• Découpage fonctionnel– Fonctions de haut niveau

– Accesseurs

– Entrée/sortie

• Implémentation– grille = tableau

– Pas de données redontantes (ex: nombre de billes)

– Gestion du score par la partie (Marble)