[C++] Jeu : Puissance 4

Discussion dans 'Web, design' créé par neku, 29 Novembre 2007.

Statut de la discussion:
Fermée.
  1. Offline
    neku Codeur roumain
    Voila, un ami devait pour son cours de prog faire un puissance 4 alors les conditions suivantes :

    - Utilisation des structures
    - Utilisation des classes
    - Utilisation de l'héritage des classes

    je lui ai donc fait ce petit jeu puissance 4 en C++
    Cette source est n'effectue pas le test sur les diagonales (il faut bien qu'il bosse un peu :p) mais c'est facilement faisable ;)

    Code:
    #include <iostream>
    #include <string>
    #include <ctype.h>
    
    using namespace std;
    
    #if defined(_MAC_) || defined(_LINUX_)
    	//Idem clrscr() Borland
    	#define clrscr() printf("\033[1;1H"); printf("\033[2J"); printf("\n");
    #elif defined(_BORLAND_)
    	#include <conio.h>
    #elif defined(_VISUAL_STUDIO_)
    	#include <cstdlib>
    	#define clrscr() system("cls");
    #else
    	#error Ce logiciel ne peut etre compile avec ce compilateur
    #endif
    
    #define PRINT(String) cout << String;
    #define PRINTCR(String) cout << String << endl;
    #define READ(Var) cin >> Var;
    
    #define BOARD_HEIGHT	10
    #define BOARD_WIDTH		10
    
    #define EMPTY_TOKEN " "
    #define SEPARATOR "|"
    #define TOKEN Token->Player->ID
    
    //Retourne FALSE si la chaine n'est pas une chaine contenant que des chiffres
    bool IsStringDigit(const string & String) {
    	bool IsDigit = false;
    	for (unsigned int Index = 0; Index < (unsigned int)String.size(); Index++) {
    		IsDigit |= (isdigit(String.c_str()[Index]) == 0);
    	}
    	return !IsDigit;
    }
    
    typedef struct Player_t {
    	unsigned int ID;
    	string Name;
    	unsigned int Color;
    };
    
    typedef struct Token_Position_t {
    	unsigned int X;
    	unsigned int Y;
    };
    
    typedef struct Token_t {
    	unsigned int ID;
    	Player_t* Player;
    	Token_Position_t Position;
    };
    
    class GameBoard {
    	public:
    		GameBoard();
    		~GameBoard();
    		
    		void InitBoard(void);
    		void ResetToken(Token_t* Token);
    		bool SetToken(Token_t* Token);
    		const Token_t* GetToken(unsigned int ID);
    		const Token_t* GetToken(const Token_Position_t* Token_Position);
    	protected:
    		const Token_t* GetFreeToken(void);
    	private:
    		Token_t* Board;
    };
    
    GameBoard::GameBoard() {
    	//Lors de l'instanciation de la classe on aloue l'espace requis pour le plateur de jeu
    	this->Board = new Token_t[BOARD_HEIGHT * BOARD_WIDTH];
    }
    
    GameBoard::~GameBoard() {
    	//Lors de la destruction on libère l'espace utilisé
    	delete []this->Board;
    }
    
    const Token_t* GameBoard::GetToken(const Token_Position_t* Token_Position) {
    	for (unsigned int Index = 0; Index < (BOARD_WIDTH * BOARD_HEIGHT); Index++) {
    		if ((this->Board[Index].Position.X == Token_Position->X) && (this->Board[Index].Position.Y == Token_Position->Y))
    			return &this->Board[Index];
    	}
    	return NULL;
    }
    
    const Token_t* GameBoard::GetToken(unsigned int ID) {
    	if (ID < (BOARD_WIDTH * BOARD_HEIGHT))
    		return &this->Board[ID];
    	return NULL;
    }
    
    bool GameBoard::SetToken(Token_t* Token) {
    	if (Token->ID < (BOARD_WIDTH * BOARD_HEIGHT)) {
    		this->Board[Token->ID] = *Token;
    		return true;
    	}
    	else {
    		return false;
    	}
    }
    
    const Token_t* GameBoard::GetFreeToken(void) {
    	for (unsigned int Index = 0; Index < (unsigned int)(BOARD_WIDTH * BOARD_HEIGHT); Index++) {
    		if (this->Board[Index].Position.X == BOARD_WIDTH && this->Board[Index].Position.Y == BOARD_WIDTH)
    			return &this->Board[Index];
    	}
    	return NULL;
    }
    
    void GameBoard::InitBoard(void) {
    	Token_t* Empty_Token = new Token_t;
    	
    	this->ResetToken(Empty_Token);
    	for (unsigned int Index = 0; Index < (unsigned int)(BOARD_HEIGHT * BOARD_WIDTH); Index++) {
    		Empty_Token->ID = Index;
    		//this->Board[Index] = *Empty_Token;
    		this->SetToken(Empty_Token);
    	}
    	
    	delete Empty_Token;
    }
    
    void GameBoard::ResetToken(Token_t* Token) {
    	Token->Player = NULL;
    	//On sort les jeton en dehors du plateau de jeu
    	Token->Position.X = BOARD_WIDTH;
    	Token->Position.Y = BOARD_HEIGHT;
    }
    
    class Puissance4 : GameBoard {
    	public:
    		Puissance4();
    		~Puissance4();
    		
    		void NewGame(unsigned int nPlayers);
    		void EndGame(void);
    		bool IsGameRunning(void);
    		void Redraw(void);
    		void Draw();
    
    		bool IsWinner(const Token_t* Token);
    		const Token_t* PlayerAction(const Player_t* Player);
    		const Player_t* GetPlayerInfos(unsigned int nPlayer);
    		
    	protected:
    		unsigned int GetY(unsigned int X);
    		void SetPlayersInfos(void);
    		
    		unsigned int nPlayers;
    		Player_t* Players;
    		bool InGame;
    };
    
    Puissance4::Puissance4(void) {
    	this->nPlayers = 0;
    	this->InGame = false;
    }
    
    Puissance4::~Puissance4(void) {
    }
    
    void Puissance4::NewGame(unsigned int nPlayers) {
    	this->InitBoard();	
    	//On reserve l'espace mémoire nécessaire au stockage des données joueur
    	this->nPlayers = nPlayers;
    	this->Players = new Player_t[nPlayers];
    	this->SetPlayersInfos();
    	this->InGame = true;
    }
    
    void Puissance4::EndGame(void) {
    	//On libère l'espace utilisé par les données joueurs
    	if (this->Players)
    		delete []this->Players;
    }
    
    void Puissance4::SetPlayersInfos(void) {
    	for (unsigned int Index = 0; Index < this->nPlayers; Index++) {
    		this->Players[Index].ID = (Index + 1);
    		PRINT("Entrez le nom du joueur " << (Index + 1) << " : ");
    		READ(this->Players[Index].Name);
    	}
    }
    
    const Player_t* Puissance4::GetPlayerInfos(unsigned int nPlayer) {
    	return (const Player_t*)&this->Players[nPlayer];
    }
    
    bool Puissance4::IsGameRunning(void) {
    	return this->InGame;
    }
    
    void Puissance4::Redraw(void) {
    	//On nettoie l'écran
    	clrscr();
    	
    	PRINTCR(" 0 1 2 3 4 5 6 7 8 9 ");
    	PRINTCR("---------------------");
    	
    	for (int Y = (BOARD_HEIGHT - 1); Y >= 0; Y--) {
    		PRINT("|")
    		for (unsigned int X = 0; X < BOARD_WIDTH; X++) {
    			bool Found = false;
    			for (unsigned int Index = 0; Index < (unsigned int)(BOARD_WIDTH * BOARD_HEIGHT); Index++) {
    				const Token_t* Token = this->GetToken(Index);
    				if (Token->Player) {
    					if ((Token->Position.X == X) && (Token->Position.Y == Y)) {
    						PRINT(TOKEN << SEPARATOR);
    						Found = true;
    						break;
    					}	
    				}
    			}
    			if (!Found) PRINT(EMPTY_TOKEN << SEPARATOR);
    		}
    		cout << endl;
    	}
    }
    
    //La partie n'a pas connu de vainqueur :/
    void Puissance4::Draw() {
    	this->InGame = false;
    	PRINTCR("La partie n'a pas connue de vanqueur !");
    }
    
    unsigned int Puissance4::GetY(unsigned int X) {
    	unsigned int nextY = 0;
    	//On recherche la prochaine place en Y d'une colonne libre
    	for (unsigned int Index = 0; Index < (unsigned int)(BOARD_WIDTH * BOARD_HEIGHT); Index++) {
    		const Token_t* Token = this->GetToken(Index);
    		//Si il s'agit d'un jeton joueur et que le X correspond à celui demandé
    		if (Token->Player && Token->Position.X == X) {
    			//Si la position du jeton trouvé + 1 est plus grand que le prochain Y deja trouvé ou 0
    			if ((Token->Position.Y + 1) > nextY)
    				nextY = Token->Position.Y + 1;
    		}
    	}
    	return nextY;
    }
    
    const Token_t* Puissance4::PlayerAction(const Player_t* Player) {
    	string Colonne;
    	const Token_t* Token = this->GetFreeToken();
    	
    	if (!Token)
    		return NULL;
    		
    	Token_t* Temp_Token = new Token_t;
    	Temp_Token->ID = Token->ID;
    
    	do {
    		do {
    			PRINT(Player->Name << ", Entrez la colonne ou placer votre jeton (0 - " << (BOARD_WIDTH - 1) << ")");
    			READ(Colonne);
    		
    			Temp_Token->Position.X = atoi(Colonne.c_str());
    		} while ((Temp_Token->Position.X > (BOARD_WIDTH - 1)) || !IsStringDigit(Colonne));
    	
    		//On recherche si il reste une place dans la colonne
    		Temp_Token->Position.Y = this->GetY(Temp_Token->Position.X);
    	} while (Temp_Token->Position.Y > (BOARD_HEIGHT - 1));
    	
    	Temp_Token->Player = (Player_t*)Player;
    	this->SetToken(Temp_Token);
    	
    	delete Temp_Token;
    	
    	return (const Token_t*)Token;
    }
    
    //On est pas fou ... on ne test pas tout les jetons ^^
    //On test uniquement le jeton qui vient d'être posé en chercher si d'autre du même joueur sont voisins ou pas ...
    bool Puissance4::IsWinner(const Token_t* Token) {
    	//Faire ici les test sur les token pour savoir si le joueur en a alligné 4 ...
    	
    	unsigned int H_Aligned = 0;
    	unsigned int V_Aligned = 0;
    	unsigned int D1_Aligned = 0;
    	unsigned int D2_Aligned = 0;
    	
    	Token_Position_t* Temp_Token_Position = new Token_Position_t;
    	
    	//Gauche
    	Temp_Token_Position->Y = Token->Position.Y;
    	for (int X = Token->Position.X - 1; (X >= 0) && (X >= ((int)Token->Position.X - 3)); X--) {
    		Temp_Token_Position->X = X;
    		const Token_t* GToken = this->GetToken((const Token_Position_t*)Temp_Token_Position);
    		//Si il y a un jeton ...
    		if (GToken) {
    			//Si le jeton appartient au même joueur et est différent de celui de départ
    			if ((GToken->Player == Token->Player) && (GToken->ID != Token->ID))
    				H_Aligned++;
    			//Sinon on arrête la boucle car il n'y a plus de contact avec une autre jeton
    			else
    				break;
    		}
    		//Sinon on arrête la boucle car il n'y a plus de contact avec un autre jeton
    		else
    			break;
    	}
    	
    	//Droite
    	for (int X = (int)Token->Position.X + 1; (X <= (BOARD_WIDTH - 1)) && (X <= ((int)Token->Position.X + 3)); X++) {
    		Temp_Token_Position->X = X;
    		const Token_t* GToken = this->GetToken((const Token_Position_t*)Temp_Token_Position);
    		if (GToken) {
    			if ((GToken->Player == Token->Player) && (GToken->ID != Token->ID))
    				H_Aligned++;
    			else
    				break;
    		}
    		else
    			break;
    	}
    	
    	//Bas
    	Temp_Token_Position->X = Token->Position.X;
    	for (int Y = (int)Token->Position.Y - 1; (Y >= 0) && (Y >= ((int)Token->Position.Y - 3)); Y--) {
    		Temp_Token_Position->Y = Y;
    		const Token_t* GToken = this->GetToken((const Token_Position_t*)Temp_Token_Position);
    		if (GToken) {
    			if ((GToken->Player == Token->Player) && (GToken->ID != Token->ID))
    				V_Aligned++;
    			else
    				break;
    		}
    		else
    			break;
    	}
    	
    	//Haut
    	for (int Y = (int)Token->Position.Y + 1; (Y <= (BOARD_HEIGHT - 1)) && (Y <= ((int)Token->Position.Y + 3)); Y++) {
    		Temp_Token_Position->Y = Y;
    		const Token_t* GToken = this->GetToken((const Token_Position_t*)Temp_Token_Position);
    		if (GToken) {
    			if ((GToken->Player == Token->Player) && (GToken->ID != Token->ID))
    				V_Aligned++;
    			else
    				break;
    		}
    		else
    			break;
    	}
    	
    	//TODO : les 4 diagonales ;)
    	
    	delete Temp_Token_Position;
    	
    	if (H_Aligned >= 3 || V_Aligned >= 3 || D1_Aligned >= 3 || D2_Aligned >= 3) {
    		this->InGame = false;
    		return true;
    	}
    	
    	return false;
    }
    
    int main (int argc, char const* argv[]) {
    	
    	Puissance4* Game = new Puissance4;
    	unsigned int nPlayers = 2;
    	
    	Game->NewGame(nPlayers);
    	
    	//On actualise le plateau de jeu
    	Game->Redraw();
    	while (Game->IsGameRunning()) {
    		for (unsigned int Index = 0; (Index < nPlayers) && Game->IsGameRunning(); Index++) {			
    			//On demande au joueur d'entrer le numéro de colonne dans laquelle il désire placer son Token
    			const Token_t* Token = Game->PlayerAction(Game->GetPlayerInfos(Index));
    			Game->Redraw();
    			//Si la fonction n'a pas retourné de Token valide cela signifie qu'il n'y a plus de place sur le plateau
    			//Et donc la partie n'a pas connue de vanqueur !!!
    			if (!Token) {
    				Game->Draw();
    			}
    			else {
    				if (Game->IsWinner(Token))
    					PRINTCR("Bravo " << Token->Player->Name << ", Tu as gagne la partie !");
    			}
    		}
    	}
    	
    	Game->EndGame();
    	
    	delete Game;
    	return 0;
    }
    Voila j'espère que ce sera utile à quelqu'un d'autre ;)
    neku, 29 Novembre 2007
    #1
  2. Online
    tqz_ Elite
    39 erreurs avec visual c++:p
    tqz_, 29 Novembre 2007
    #2
  3. Offline
    ailless Asimov, Sagan, Carlin, Hitchens
    C'est quoi les options de compilation de ton compilateurs neku ?
    ailless, 29 Novembre 2007
    #3
  4. Offline
    neku Codeur roumain
    Je suis sous OS x et j'utilise g++:
    $

    rien de vraiment particulier

    Déjà avec visual studio tu n'aura pas de fonction clrscr() ...

    Code:
    void clrscr(){
    system("cls");
    }
    peux-tu me copier la liste des erreurs ?
    neku, 29 Novembre 2007
    #4
  5. Offline
    ailless Asimov, Sagan, Carlin, Hitchens
    Quand je serai sur linux, je testerai la compilation pour comparer si tu veux, là je fais du COBOL >.< :)
    ailless, 29 Novembre 2007
    #5
  6. Offline
    ailless Asimov, Sagan, Carlin, Hitchens
    J'ai beaucoup d'erreurs de compilations (sur linux) aussi mais faut que je corrige les premières pour avoir les autres donc je peux pas te montrer toutes les erreurs mais beaucoup d'erreurs viennent de mots séparés => v oid, unsig ned
    je sais pas comment ça peut compiler chez toi héhé :)

    ensuite #include <cctype> et pas ctype.h
    ailless, 2 Décembre 2007
    #6
  7. Offline
    neku Codeur roumain
    les espaces dans les noms de types ou autres ce n'est pas ma faute, c'est le balise CODE du forum qui génère se bug, après ca, moi je l'ai compilé sous Windows avec VS hier soir et aucuns soucis ...
    neku, 2 Décembre 2007
    #7
  8. Offline
    ailless Asimov, Sagan, Carlin, Hitchens
    wep mais faut voir tes options de compilations aussi, ça joue beaucoup

    en C :

    gcc -o test test.c passera sûrement alors que
    gcc -W -Wall -pedantic -o test test.c laissera rien passer mais bon t'es meilleur programmeur que moi donc tu le sais sûrement

    maintenant je vais demander à un ami de le compiler chez lui aussi on verra bien :)
    ailless, 2 Décembre 2007
    #8
Statut de la discussion:
Fermée.