BOOKS i'm reading |
/* * Module ID: chess.h * Titre : Declaration de classes pour le jeu d'echec * * Auteur : Olivier Langlois <olivier@olivierlanglois.net> * Date : 4 Fevrier 1998 * */ #ifndef _CHESS_H_ #define _CHESS_H_ #include "collect/idlist.h" #include <iostream> /* * Definitions */ #define NUMROW 8 #define NUMCOL 8 /* * Declarations partielles */ class ChessBoard; class Column; class ChessCase; class GamePiece { private: // Position de la piece. ChessCase *position; public: GamePiece() : dx(NULL), dy(NULL), position(NULL) {} GamePiece( ChessCase *Case ) : dx(NULL), dy(NULL), position(Case) {} virtual ~GamePiece() = 0; /* * Fonctions Setters */ void setPos( ChessCase *pos ) { position = pos; } /* * A l'origine, les fonctions visit*() avaient tous le nom visit. * Tant qu'il n'existe pas de classe derivee qui override aucune de ces * fonctions cela ne cause aucun probleme puisque le compilateur performe un * 'name mangling' a partir du nom ET des parametres. * Cependant, des qu'une classe possede une fonction qui override une des * fonctions visit*, elle cache les autres. */ virtual void visitCase( ChessCase &Case ); virtual void visitCol( Column &col ); virtual void visitBoard( ChessBoard &board ); protected: /* * Variables qui definit les deplacements possibles de la piece. */ int numMove; int *dx, *dy; }; class Knight : public GamePiece { public: Knight() {init();} Knight( ChessCase *initialPos ) { init(); setPos(initialPos); } ~Knight(); private: void init(void); }; class ChessCase : public IsvDlink { private: // Piece presente sur la case. GamePiece *presentPiece; protected: ChessBoard *Board; /* * La presence de la position dans cette classe peut sembler redondante * puisqu'elle doit etre connue pour atteindre la case. Cependant, lorsque * l'on desire faire interagir la case avec une piece, les objets doivent * avoir un moyen d'acceder a cette information. Cela aurrait pu etre * accompli de d'autres facons: * * 1 - Passer la position aux fonctions necessitant cette information * * 2 - La position aurrait pu etre contenue dans les objets de pieces * (Mauvaise idee car elle aurrait du etre ajustee a chaque * deplacement) * * En conclusion, la presence de la position dans la classe ChessCase * semble etre la meilleure solution car elle necessite qu'une seule * initialisation puisqu'il est tres peu probable que les cases ait a se * deplacer. */ int x, y; public: /* * Les valeurs par defaut de x & y sont choisies loin des coordonnees du * jeu de sorte que si jamais par erreur une Piece tentait de se deplacer a * partir d'une case non-initialisee qu'il soit impossible pour n'importe * quel (dx,dy) que la piece se retrouve sur le Chessboard. */ ChessCase() : presentPiece(NULL), x(-256), y(-256) {} /* * Ce constructeur a peu de chance d'etre utilise frequemment car il est * anticipe que les objets seront construit en array la majorite du temps, * situation ou le constructeur par defaut est appelle. */ ChessCase( int new_x, int new_y, GamePiece *piece = NULL ) : x(new_x), y(new_y), presentPiece(piece) {} virtual ~ChessCase() {} virtual void init( void ) {} virtual void print( ostream &os ) {} // Fonctions Setters void setBoard( ChessBoard *cb ) { Board = cb; } void setPiece( GamePiece *piece ) { presentPiece = piece; } void setPosition( int new_x, int new_y ) { x = new_x; y = new_y; } // Fonctions Getters void getPosition( int &xRef, int &yRef ) { xRef = x; yRef = y; } virtual void accept( GamePiece &piece ) { piece.visitCase(*this); } }; /* * La classe Column permet de creer l'operateur [Column][Row] pour la classe * ChessBoard. */ class Column : public IsvDlink { public: Column(); virtual ~Column() {} ChessCase &operator[](int i) { return *dynamic_cast<ChessCase *>(ChessCases[i]); } virtual void print( ostream &os, int y = -1 ); virtual void accept( GamePiece &piece ) { piece.visitCol(*this); } protected: friend class ChessBoard; /* * ChessCases est alloue dynamiquement, ce qui permet eventuellement de * remplacer ChessCases par des objets d'une classe derivee de ChessCase. */ // ChessCase *ChessCases; /* * Une liste a du etre utilisee pour contenir les cases car un pointeur * de classe ne peut avoir une reference correcte sur une chaine d'objets * d'une classe derivee. */ IDList ChessCases; /* * Ce constructeur doit etre utilise par les classes derivee de Column * qui doivent assigner une des objets d'un classe derivee de ChessCase * a ChessCases. */ Column(int) {} virtual void initCases( int x, ChessBoard *cb ); }; class ChessBoard { public: /* * Il est important d'appeler initColumns() apres l'appel du constructeur * Cela ne peut pas etre fait a l'interieur du constructeur car l'appel * de fonctions virtuelles a l'interieur de constructeur est deconseille. */ ChessBoard(); virtual ~ChessBoard() {} Column &operator[](int i) { return *dynamic_cast<Column *>(columns[i]); } virtual void initColumns( void ); virtual void print( ostream &os ); /****************************************************************************** * * Nom : accept * * Utilite : Recoit une piece. * * Parametres: * piece (GamePiece &) Piece a deplacer. * * Valeur de retour: Aucune. * ****************************************************************************/ virtual void accept( GamePiece &piece ) { piece.visitBoard(*this); } protected: /* * columns est alloue dynamiquement, ce qui permet eventuellement de * remplacer columns par des objets d'une classe derivee de Column. */ // Column *columns; /* * Une liste a du etre utilisee pour contenir les cases car un pointeur * de classe ne peut avoir une reference correcte sur une chaine d'objets * d'une classe derivee. */ IDList columns; /* * Ce constructeur doit etre utilise par les classes derivee de ChessBoard * qui doivent assigner des objets d'un classe derivee de Column * a columns. */ ChessBoard(int) {} }; ostream &operator <<( ostream &os, ChessBoard &s ); ostream &operator <<( ostream &os, ChessCase &s ); #endif /* _CHESS_H_ */ |