Projet Dame

SOMMAIRE

 

I. Introduction *

II. Présentation générale du jeu Dam'NATION *

A. Les règles du jeu *

B. Représentation des coups *

1. Le damier *

2. La structure initiale *

3. La structure retenue *

C. Les différentes listes de coup *

1. La liste de pions jouables *

2. La liste des coups possibles *

3. La liste optimale *

D. Le Min Max *

1. La représentation *

2. Le concept d’évaluation *

3. La réalisation *

E. Le Alpha Beta *

1. Le concept d’élimination *

F. Les stratégies *

1. Offensivité de nombre *

2. Offensivité de position *

G. Choix de la plate-forme de travail *

H. Présentation générale *

I. Méthode de programmation *

J. Les problèmes rencontrés *

III. Problèmes rencontrés et impressions *

A. Le travail de groupe *

B. Les limites et améliorations *

C. Les problèmes rencontrés *

1. Générique *

2. Algorithmique *

IV. Listing de Dam'Nation *

A. DamnationView.h *

B. DamnationView.cpp *

C. DamnationDoc.h *

D. DamnationDoc.cpp *

E. Damnation.h *

F. Damnation.cpp *

I. Introduction

 Dam'Nation a pris naissance durant le mois de novembre 1996, lorsque nous avons choisi de faire un jeu de dame, comme projet d'algorithmique.

Un groupe de travail s'est alors constitué, et nous nous somme retrouvés trois dans la même équipe: Apollon Philippe Eldin, Azimof Frédéric Jolin et Beno Stéphane Benoliel. Nous avons trouvé un intérêt commun, c'est à dire de relever le défit de la création d'un jeu de dames. Nous pensions que c’était un jeu simple de conceptions mais qui demandait une bonne maîtrise de l'outil informatique, et de l'utilisation des pointeurs.

Nous avons alors réalisé un cahier des charges, pour établir un plan de conception. Nous avons fait le bilan des compétences de chacun pour une meilleure optimisation du travail. Nous avons partagé ensuite le travail et réalisé une première version. Nous nous sommes aperçus alors de la difficulté du travail de groupe, mais également des avantages.

 Nous avons donc mis au point un jeu de dame sous le nom de Dam'Nation, par une inspiration soudaine. La réalisation du jeu s'est faite sous l'outil de développement de Microsoft Visual C++, fonctionnant sous Windows. Cet outil nous a permis d'obtenir un résultat agréable et convivial.

 Nous allons donc vous présenter tout au long de ce rapport : les règles choisies, les structures adoptées... puis une présentation de notre algorithme, une présentation du graphisme et finalement nos impressions et nos conclusions.

II. Presentation générale du jeu Dam'NATION

A. Les règles du jeu

La règle majeure de notre jeu est la prise obligatoire et maximale.

Les déplacements des pions sont classiques: prise d’un pion adverse adjacent, poursuite de la prise si la condition précédente est réalisée

Un pion fait dame uniquement si sa dernière case d’arrivée est au bout du damier ( pas de pion transformé en dame durant une prise de pions )

Une dame se déplace librement le long d'une ligne vide. Si elle rencontre un pion adverse elle le prend et peut changer de direction juste après pour continuer la prise toujours en parcourant une ligne vide jusqu'au prochain pion adverse.

B. Représentation des coups

1. Le damier

Notre damier est en fait un tableau de 12 par 12 cases, les bordures ( numéro 0 et 11 ) sont là pour vérifier les débordements. Il faut remarquer que notre numérotation des cases n'est pas usuelle pour le jeu de dame, mais c'est avec cette convention que nous avons réalisé le programme.

typedef int TAB[12][12];

TAB t;

2. La structure initiale

La structure choisie initialement pour un coup joué était une liste de coordonnées du pion ou de la dame ( premier élément de la liste = les coordonnées de la pièce déplacée, les autres éléments de la liste sont les coordonnées des points de chute de la pièce).

struct typedef coup

{

int x ;

int y ;

struct coup *suivant ;

} COUP, *pCOUP;

struct typedef liste

{

pCOUP coup ;

struct liste *suivant ;

}

Cette structure a cependant été abandonnée, au profit d'une autre moins gourmande en mémoire et plus pratique pour les tests.

3. La structure retenue

typedef struct deplacement

{

int d ;

struct depl *suiv ;

} DEPLACEMENT, *pDEPLACEMENT ;

 typedef struct coup

{

int x ;

int y ;

struct coup *suiv ;

pDEPLACEMENT dir ;

} COUP, *pCOUP ;

 pCOUP ptr_coup ;

 Ici la pièce jouée est représentée par ses coordonnées dans ptr_coup->x et ptr_coup->y. Pour ses déplacements il s'agit d'une liste de déplacement pointée par ptr_coup->dir. La direction est représentée par un entier k de la manière suivante: k= ptr_coup->dir->d

Dans cet exemple, les blancs jouent dans la direction de la flèche. Pour les noirs, c'est la même chose par rapport à leur sens de déplacement.

Nous avons donc abouti à la création d'un type TAB1:

typedef struct direction

{

int x ;

int y ;

} COORD, TAB1[4] ;

TAB1 d={ {1,-1},{-1,-1},{-1,1},{1,1} } ;

Ce qui nous donne les formules suivantes pour calculer les déplacements dx et dy :

k= ptr_coup->dir->d ;

nbr_de_case=(k/4)+1; /* donne l'amplitude */

k=k%4; /* donne la direction */

dx=nbr_de_case*d[k].x*couleur; /* couleur = blanc (1) ou noir (-1) */

dy= nbr_de_case *d[k].y*couleur;

On peut ainsi atteindre la case désirée t[x+dx][y+dy].

C. Les différentes listes de coup

1. La liste de pions jouables

Que ce soit le joueur ou l'ordinateur qui va jouer, le programme crée une liste de tous les pions jouables de la couleur appropriée avec la fonction pCOUP list_pion_jouable (TAB t, int couleur). La liste obtenue se présente sous la forme d'une liste de tous les pions jouables avec pour chacun de ces pions une liste de toutes les directions possibles pour le premier déplacement uniquement et en tenant compte de l'obligation de prendre.

Par exemple un pion en ( X ,Y ) qui peut bouger dans les quatre directions en prenant donnera le maillon suivant : ( X , Y ) { 0,1,2,3 }

Pour un pion qui ne peut effectuer qu'un déplacement à gauche et à droite, le maillon est :

( X , Y ) { 0,1 }

Il faut remarquer ici que lors d'une prise, le déplacement fait arriver la pièce prenante sur la pièce prise. La prise véritable est effectuée lorsqu'on joue réellement sur le damier.

2. La liste des coups possibles

De la liste de pions jouables, nous tirons la liste de pions des coups jouables suivant la complexité ( prise obligatoire ou non ) grâce à la fonction :

int trouver_coup(TAB t,pCOUP tete, int profondeur, int complexite)

Cette fonction, part de la liste de pions jouables et pour chaque déplacement possible, la fonction crée une liste de tous les coups possibles avec la liste de déplacements a effectuer pour jouer le coup. trouver_coup rend également le nombre maximum de déplacements ce qui correspond au maximum de pions que peut prendre le joueur considéré.

Par exemple si la liste modifiable se réduit à un pion qui peut avancer à gauche et à droite, la liste des pions jouables { ( X , Y ) { 0 , 1 } } devient en passant par trouver_coup la liste suivante:

{ ( X , Y ) { 0.... } , ( X , Y ) { 1....} } .

3. La liste optimale

La fonction renvoie une liste dans laquelle se trouvent les coups de n déplacements ( tenant compte des règles : prise obligatoire ou non ; prise maximale ) . Il y a donc un écrétage de la liste des coups possibles.

 

 

 Gestion du jeu

D. Le Min Max

Résumé des pages 25,26 du polycopié sur les structure de données de Jean Sequiera

1. La représentation

A l'aide d'un arbre nous allons représenter l'ensemble des situations possibles. Nous appellerons racine l'état initial du jeu, les " branches " sont les situations envisagées par l'un des deux joueurs Un phénomène embranchement permet de décrire une situation avec anticipation.

2. Le concept d'évaluation

Afin d'évaluer une situation nous avons choisi de faire la différence des pièces sur le damier cette valeur représente alors le degré de favorabilité du coup .

3. La réalisation

Si plusieurs choix sont possibles

L'ordinateur va jouer successivement les pions noirs puis les pions blancs jusqu'à une " profondeur " de réflexion choisi par l'utilisateur

Après avoir joué " profondeur " fois l'ordinateur va backtraquer en remontant l'évaluation de la situation

A chaque remontée l'ordinateur comparera de proche en proche la valeur remontée avec celle déjà présente

Il prendra soit le Min soit le Max

La valeur parvenant à la racine indique , la situation la plus favorable.

Remarque le niveau 1 de la recherche du min max correspond approximativement à notre prise maximale. En fait l'absence de cette règle aurait grandement simplifié les choses

E. Le Alpha Beta

1. Le concept d'élimination

Nous pouvons améliorer l'algorithme MinMax grâce à l'Alpha Bêta.

Cette méthode consiste à éliminer une partie de l'exploration des situations.

Nous allons comparer un noeud de niveau n et un noeud de niveau (n+1) sur des branches différentes .

Nous effectuons l'exploration jusqu'à trouver un sous-fil dont la valeur est inférieure à une valeur de référence ( paramètre supplémentaire dans l'appel de la fonction ) ( celle du niveau n ... ) alors on scie la branche.

F. Les stratégies

1. Offensivité de nombre

L'évaluation se fait par différence entre le nombre de pions blancs et celui de pions noirs . Il arrive parfois qu'une situation amène à une même différence alors nous prenons une valeur de référence celle du nombre de pions noirs que l'on compare de proche en proche. C'est un test supplémentaire en plus du Min Max et de Alpha Beta un paramètre supplémentaire dans la fonction récursive

2.Offensivité de position

Lorsqu'une situation a la même évaluation comme c'est le cas assez souvent en début de partie l'ordinateur va avancer en priorité les pions de son arrière garde c'est à dire ceux qui sont le moins vulnérables

Gestion du graphisme

Le graphisme est une partie entière de notre projet, qui nous a demandé comme tout le reste de nombreuses heures de travail. Voici ce que nous avons fait et pourquoi.

G. Choix de la plate-forme de travail

Nous avons choisi de programmer notre jeu de dame sous l'environnement Windows de Microsoft. Ce choix fut prix à la suite d'une étude de marché telle qu'elle aurait été faite dans une optique de création d'un logiciel à vocation commerciale. Cet environnement nous a apporté de nombreux avantages.

Windows est le système d'exploitation le plus utilisé auprès du grand public, utilisateur de micro-ordinateur. En effet, c'est le second système d'exploitation utilisé après l'incontournable UNIX, mais plus adapté au marché de la microinformatique domestique. Ce serait alors une erreur de vouloir fabriquer un logiciel de jeu dans une optique de vente, sous l'environnement UNIX pour deux raisons. La première est qu' UNIX n'est pas consacré au jeu, bien que l'on puisse en trouver une quantité non négligeable. La seconde est que les concepteurs de logiciels de jeux sous UNIX ont opté pour la plupart, pour une distribution gratuite, en utilisant le principe du freeware. 

L'environnement Windows est, depuis les dernières versions (Windows 95 et NT ) un système d'exploitation 32bits. Nous avons donc choisi de produire notre jeu pour les plates-formes 32bits, en misant sur l'expansion des jeux Windows, due à l'évolution du matériel (apparition des premiers Pentiums MMX, par exemple).

Notre outil de programmation fut, le Visual C++ 4.0, Développer Studio, le logiciel de développement de Microsoft. L'aspect intuitif et l'intégration de modules pré-programmés représentent la motivation principale de ce choix. Il a donc fallut apprendre de A à Z un nouveau langage, qui se base sur le C, mais avec l'évolution des langages objets.

H. Présentation générale 

Notre logiciel se compose donc de plusieurs modules. Le premier, et le plus important, est la fenêtre principale où se trouve le damier. Puis les menus, la barre d'outils et la barre des tâches. Et finalement une aide qui permet de répondre à toutes les questions sur le jeu.

Le logiciel est en fait une SDI, c'est à dire une fenêtre de travail unique, tel que le bloc note de windows par exemple. L'intérieur est du type Form, telle une boite de dialogue, permettant cet aspect grisé, à la place d'un fond blanc classique. Le damier est une succession de bitmaps que nous avons produit sous 3D Studio Max, pour permettre une impression de relief. Nous nous excusons au prés des néophytes du jeu de dames, n'ayant pas reproduit des pions cylindriques, mais sphériques et n'ayant pas du tout respecté les couleurs, blanche et noire.

 

Un menu a été élaboré pour répondre au besoin de l'utilisateur: une partie Jeu avec les commandes permettant de commencer une partie, quitter une partie, et choisir un des trois niveaux de jeu; une partie Affichage qui permet d'afficher ou non la barre d'outils et la barre des taches. Et une dernière partie ? qui fait référence à l'aide. La barre d'outils n'est qu'une autre façon d'accéder aux commandes des menus.

Pour guider l'utilisateur, une barre d'état indiquant, en fonction de la position de la souris les commandes qu'il peut exécuter. Pour répondre plus précisément aux différentes questions, un fichier d'aide peut être lancé grâce à un clique sur le bouton:

La copie d'écran ci-dessus montre en détail tout les éléments décrits.

Pour jouer il suffit d'utiliser la souris en cliquant avec le bouton gauche sur les cases à parcourir puis de valider le coup grâce au bouton gauche. C'est donc très simple d'utilisation. J  

I. Méthode de programmation

La programmation sous Visual C++ fait appel à des notions de programmation objet pour la gestion des événements. En effet nous avons utilisé une classe particulière pour la vue, la classe CDamnationView. Cette classe contient l'essentiel du code de notre jeu et se décompose en trois parties:

Le fichier entête contenant les déclarations.

La partie gestion des événements comme la gestion de la souris, de l'affichage...

La partie algorithme de réflexion et de contrôle des règles de jeu.

Comme vous l'avez déjà vu, notre damier est un tableau d'entier de (12 x 12). Nous avons utilisé cela pour gérer l'affichage dans la fonction OnDraw. Cette fonction est consacrée à l'affichage, mais également au réaffichage dans le cas où la fenêtre est redimensionnée par exemple. Il suffit donc, pour chaque changement de tableau, c'est à dire pour chaque modification du jeu, de réafficher l'ensemble du damier. C'est exécuter grâce à la fonction Invalidate().

La gestion de la souris se passe en deux étapes, quand on appuie sur le bouton gauche et quand on appuie sur le bouton droit.

Un premier clique sur le bouton gauche crée un nouveau coup en entrant les cordonnées x et y, avec un déplacement nul et pas de suivant. Les autres cliques évaluent le déplacement puis l'ajoutent en queue de liste.

Un clique sur le bouton droit lance l'opération de jeu, c'est à dire:

pour le joueur:

Recherche des coups possibles sur le damier.

Comparaison avec le coup du joueur.

Exécution du coup.

Affichage du damier.

pour l'ordinateur:

Recherche du meilleurs coups possibles grâce à l'algorithme dite du Min-Max.

Exécution du coup.

Affichage du damier.

Pour le calcul des déplacements, on compare les coordonnées saisies avec les précédentes. Supposons que les anciennes coordonnées soient xold et yold et les nouvelles x et y on a alors le déplacement k :

k=a+b*4 avec a=0, 1, 2 ou 3 en fonction de la direction

et b=abs(x-xold)=abs(y-yold)

Nous pouvons simplement retrouver la direction.

J. Les problèmes rencontrés

Les problèmes que nous avons rencontrés sont de plusieurs types. Les uns ont été résolus, les autres non.

Le premier problème a été l'apprentissage de la programmation sous Visual C++, qui nous a demandé un peu de temps, mais qui ne fut pas un problème majeur.

Le second problème a été celui de la gestion des classes MFC qui gèrent automatiquement un certain nombre de taches, et qui nous permet entre autre de configurer les gestions du clavier et de la souris.

Mais le troisième et dernier problème est le plus important, et reste jusqu'ici sans solution. Comment faire pour gérer le réaffichage de l'écran, avant que la routine permettant à l'ordinateur de jouer, se lance? Nous avons en effet un problème visuel qui pose des difficultés à l'utilisateur. Quand le joueur joue, le damier ne ce réaffiche que quand l'ordinateur a fini de jouer. En fait il exécute deux Invalidate() à la suite. Nous avons essayé de gérer ce problème grâce à un timer qui aurait comme tâche de lancer le réaffichage en tache de fond, en créant un autre handle. Mais nous n'avons pas pu aboutir dans cette voie.

Si nous avions eu plus de temps, nous comptions réaliser plusieurs choses. Pouvoir sauvegarder une partie en cours, ce qui ne demande en fait pas beaucoup de chose, puisqu'il suffit de sauvegarder le tableau de l'état du damier. Gérer le fait que l'on ne puisse pas changer de niveau de difficultés en cours de partie. Améliorer l'affichage avec une visibilité plus importante des déplacements et notamment l'incrustation de séquences animées rendant le jeu plus attractif (surtout à l'ère du multimédia).

Finalement nous pensons que le choix de Windows et de Visual C++ nous a permis de réaliser une interface très conviviale, intuitive et esthétique. Nous sommes fiers de pouvoir vous présenter le fruit de notre travail au travers de celle-ci. Même s'il est exact que ce n'est pas l'habit qui fait le moine, l'aspect extérieur à une importance primordiale pour marquer une différence, et pour pouvoir conquérir un marché.

De plus nous ne regrettons pas d'avoir investi un peu de temps dans l'apprentissage de logiciel tel que Visual C++, cela pourra toujours nous servir plus tard, dans notre vie professionnelle.

III. Problèmes rencontrés et impressions

A. Le travail de groupe

L'intégration dans un travail de groupe est une des difficultés que l'on peut rencontrer lors de la réalisation d'un projet de ce type. Mais au delà de nos différents, nous pouvons profiter de cet avantage pour faire un travail plus constructif et plus intéressant. La première chose à faire est de bien partager le travail en profitant au maximum des qualités et des compétences de chacun. En effet nous avons partagé le travail en tenant compte de ce facteur. Stéphane s'est penché plus particulièrement vers la programmation de la partie graphique, ayant déjà vu le mécanisme de programmation sous windows. Philippe et Frédéric ont quand à eux élaboré la gestion des listes et le mécanisme fondamental de l'algorithme. C'est ensuite dans un effort collectif que nous avons fini la mise au point du jeu, notamment durant l'intégration des dames.  

Un point intéressant à remarquer est le fait que le travail de groupe apporte de nombreux avantages, et un certain recul nécessaire à l'analyse de la situation. Il est vrai que de n'avoir aucune vue d'ensemble ne favorise pas l'avancement du projet. La motivation dûes au groupe est aussi importante et nécessaire. Il y a toujours un membre pour aider les autres lors d'une période de démotivation.

La difficulté principale est la coordination du travail qui demande un investissement personnel non négligeable. Mais au delà de cela c'est une expérience intéressante et proche de la réalité dans l'entreprise.

B. Les limites et améliorations

La mise en oeuvre de l'alpha beta, nous permettrait un gain important de temps puisque l'on peut presque doubler la profondeur pour le même temps de recherche du meilleur coup.

Pour la mémoire, il faudrait pouvoir éviter de passer un tableau en paramètre et donc favoriser une fonction qui déjouerait mais cette opération s'avère délicate avec la règle de la prise maximale.

Il pourrait être aussi intéressant de coder les coordonnées des pièces avec un seul entier de type char pour des configurations un peu faibles en ressources mémoire.

C. Les problèmes rencontrés

1. Générique

Problème de compréhension des listing des autres. Suite à ce travail de groupe il apparaît évident que nous ne commentons pas assez nos listing ( perte de temps pour les autres et pour celui qui a oublié les commentaires puisqu'il est obligé de le réexpliquer )

Optimisation du code très délicate, toujours à cause du manque de commentaire.

La plus grosse erreur a été de ne pas mettre en place un algorithme clair sur papier avec une séparation modulaire des différents problèmes avec paramètres clairement définis pour que chacun puisse apprécier les avancées des autres.

2. Algorithmique

Choix des structures

Mise en place de l'alpha beta et des stratégies de la fonction déjouer

IV.Listing de Dam'Nation

A. DamnationView.h

// DamnationView.h : interface of the CDamnationView class

//

/////////////////////////////////////////////////////////////////////////////

 

typedef struct direction

{

int x;

int y;

} COORD, TAB1[4];

 

typedef struct depl

{

int d;

struct depl *suiv;

} DEPLACEMENT, *pDEPLACEMENT;

 

typedef struct coup

{

int x;

int y;

struct coup *suiv;

pDEPLACEMENT dir;

} COUP, *pCOUP;

 

typedef struct coup2

{

int x;

int y;

struct coup2 *suiv;

}COUP2, * pCOUP2;

 

typedef int TAB[12][12];

 

 

 

////////////////////////////////////////////////////////////

 

class CDamnationView : public CFormView

{

protected: // create from serialization only

CDamnationView();

DECLARE_DYNCREATE(CDamnationView)

 

public:

//{{AFX_DATA(CDamnationView)

enum{ IDD = IDD_DAMNATION_FORM };

// NOTE: the ClassWizard will add data members here

//}}AFX_DATA

 

// Attributes

public:

CDamnationDoc* GetDocument();

CBitmap* pImage[6];

 

//// declaration algo en public ////////

pCOUP coupjoueur;

TAB t;

TAB1 d;

int prof_max;

int max;

pCOUP coup_trouver;

pDEPLACEMENT depl_trouver;

int xorg,yorg;

int profondeur_max;

 

// Operations

public:

 

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CDamnationView)

public:

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

virtual void OnInitialUpdate();

protected:

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

virtual void OnDraw(CDC* pDC);

//}}AFX_VIRTUAL

 

// Implementation

public:

virtual ~CDamnationView();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

 

// Generated message map functions

public:

//{{AFX_MSG(CDamnationView)

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

afx_msg void OnRButtonDown(UINT nFlags, CPoint point);

afx_msg void OnButton1();

afx_msg void OnButton2();

afx_msg void OnButton3();

afx_msg void OnTimer(UINT nIDEvent);

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

 

public:

 

// algorithme principal//////////////////////////////

void damier_vide (TAB t);

void damier_particulier (TAB t, int i);

void init (TAB t);

void copie_tableau (TAB t,TAB ttmp);

pCOUP cree_coup (int c, int l, pDEPLACEMENT direction ,pCOUP suivant );

pCOUP ajoute_coup_queue (pCOUP tete, pCOUP suivant);

pCOUP ajoute_coup_tete (pCOUP tete, pCOUP suivant);

pCOUP defiler_coup_tete (pCOUP tete);

pCOUP defiler_coup_queue (pCOUP tete);

pCOUP meilleur_coup_dune_list (pCOUP tete, int max);

pCOUP copie_list_coup (pCOUP p);

pCOUP recherche (pCOUP list, pCOUP tete);

int compter_deplacement (pCOUP tete);

pDEPLACEMENT defiler_deplacement_tete (pDEPLACEMENT tete);

pDEPLACEMENT defiler_deplacement_queue (pDEPLACEMENT tete);

pDEPLACEMENT cree_deplacement (pDEPLACEMENT suivant, int d );

pDEPLACEMENT ajoute_deplacement_queue (pDEPLACEMENT tete, pDEPLACEMENT suivant);

pDEPLACEMENT copie_list_deplacement (pDEPLACEMENT p);

pDEPLACEMENT test_deplacement (TAB t, int c, int l ,int couleur, int test_simple);

int test_complexite (TAB t, int couleur );

pCOUP list_pion_jouable (TAB tt, int couleur);

pCOUP coup_pour_rien (int num);

pCOUP jouer_direction (TAB damier, pCOUP tete);

pCOUP jouer_coup (TAB damier, pCOUP tete);

pCOUP list_optimale (TAB t,int couleur);

int trouver_coup (TAB t,pCOUP tete, int profondeur, int complexite);

int action_dun_coup (TAB t,int couleur);

int joueur_joueur (void);

pCOUP jouer_ordi (TAB t, pCOUP liste, int couleur);

pCOUP liberation (pCOUP tete);

int test_victoire (TAB t);

void creation_dame (TAB t,int couleur);

int score_tableau (TAB t);

int meilleur_coup (TAB t, pCOUP tete,int couleur, int profondeur);

/// FIN ALGO PRINCIPAL /////////////////////

void afficher_list_coup (pCOUP tete);

 

protected:

};

 

#ifndef _DEBUG // debug version in DamnationView.cpp

inline CDamnationDoc* CDamnationView::GetDocument()

{ return (CDamnationDoc*)m_pDocument; }

#endif

 

/////////////////////////////////////////////////////////////////////////////

 

B. DamnationView.cpp

// DamnationView.cpp : Code source de la class View...

//

 

#include "stdafx.h"

#include "Damnation.h"

 

#include "DamnationDoc.h"

#include "DamnationView.h"

//////////////////////////////////////////////////////////

 

#define joueur 1

#define ordi -1

 

#define blanc 1

#define noir -1

 

#define vide 0

#define out 69

#define pbl blanc

#define pno noir

#define dbl 2*blanc

#define dno 2*noir

#define simple 1

#define complexe 0

 

//////////////////////////////////////////////////////////

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationView

 

IMPLEMENT_DYNCREATE(CDamnationView, CFormView)

 

BEGIN_MESSAGE_MAP(CDamnationView, CFormView)

//{{AFX_MSG_MAP(CDamnationView)

ON_WM_LBUTTONDOWN()

ON_WM_RBUTTONDOWN()

ON_COMMAND(ID_BUTTON_1, OnButton1)

ON_COMMAND(ID_BUTTON_2, OnButton2)

ON_COMMAND(ID_BUTTON_3, OnButton3)

ON_WM_TIMER()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationView construction/destruction

 

CDamnationView::CDamnationView()

: CFormView(CDamnationView::IDD)

{

//{{AFX_DATA_INIT(CDamnationView)

// NOTE: the ClassWizard will add member initialization here

//}}AFX_DATA_INIT

// TODO: add construction code here

d[0].x=1;d[0].y=-1;

d[1].x=-1;d[1].y=-1;

d[2].x=-1;d[2].y=1;

d[3].x=1;d[3].y=1;

prof_max=0;

max=0;

coup_trouver=NULL;

coupjoueur=NULL;

profondeur_max=3;

}

 

CDamnationView::~CDamnationView()

{

}

 

void CDamnationView::DoDataExchange(CDataExchange* pDX)

{

CFormView::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CDamnationView)

// NOTE: the ClassWizard will add DDX and DDV calls here

//}}AFX_DATA_MAP

}

 

BOOL CDamnationView::PreCreateWindow(CREATESTRUCT& cs)

{

// TODO: Modify the Window class or styles here by modifying

// the CREATESTRUCT cs

 

return CFormView::PreCreateWindow(cs);

}

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationView diagnostics

 

#ifdef _DEBUG

void CDamnationView::AssertValid() const

{

CFormView::AssertValid();

}

 

void CDamnationView::Dump(CDumpContext& dc) const

{

CFormView::Dump(dc);

}

 

CDamnationDoc* CDamnationView::GetDocument() // non-debug version is inline

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDamnationDoc)));

return (CDamnationDoc*)m_pDocument;

}

#endif //_DEBUG

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationView message handlers

 

 

 

void CDamnationView::OnInitialUpdate()

{

CFormView::OnInitialUpdate();

// TODO: Add your specialized code here and/or call the base class

// chargement des images dans le tableau

int c,l;

 

 

pImage[0]=new CBitmap;

pImage[0]->LoadBitmap(IDB_CASEBLANCHE);

 

pImage[1]=new CBitmap;

pImage[1]->LoadBitmap(IDB_CASENOIRE);

 

pImage[2]=new CBitmap;

pImage[2]->LoadBitmap(IDB_PIONBLANC);

 

pImage[3]=new CBitmap;

pImage[3]->LoadBitmap(IDB_PIONNOIR);

 

pImage[4]=new CBitmap;

pImage[4]->LoadBitmap(IDB_DAMEBLANCHE);

 

pImage[5]=new CBitmap;

pImage[5]->LoadBitmap(IDB_DAMENOIRE);

 

// initialisation du premier damier

for (c=0; c<12 ; c++)

for (l=0; l<12 ; l++)

t[c][l]=out;

for (c=1; c<6 ; c++)

for (l=1; l<6 ; l++)

{

t[2*c][(2*l)-1]=vide;

t[(2*c)-1][2*l]=vide;

}

 

for (c=1; c<6 ; c++)

{

for (l=1; l<3 ; l++)

{

t[(2*c)][(2*l)-1]=pno;

t[(2*c)-1][2*l]=pno;

}

for (l=4; l<6 ; l++)

{

t[(2*c)][(2*l)-1]=pbl;

t[(2*c)-1][2*l]=pbl;

}

}

//insert fin

damier_particulier(t,15); // déclaration d'un damier particulier

 

}

 

// fonction permettant le réaffichage de l'écran

void CDamnationView::OnDraw(CDC* pDC)

{

int i,j;

CDC* pMemDC;

pMemDC=new CDC;

pMemDC->CreateCompatibleDC(pDC);

 

for (i=1;i<11;i++) // pour chaque case du tableau trace le bitmpas qui correspond

for (j=1;j<11;j++)

{

if (t[i][j]==pno )

{

pMemDC->SelectObject(pImage[3]);

pDC->BitBlt(10+(35*i),10+(35*j),35,35,pMemDC,0,0,SRCCOPY);

}

else if (t[i][j]==pbl )

{

pMemDC->SelectObject(pImage[2]);

pDC->BitBlt(10+(35*i),10+(35*j),35,35,pMemDC,0,0,SRCCOPY);

}

else if (t[i][j]==dbl )

{

pMemDC->SelectObject(pImage[4]);

pDC->BitBlt(10+(35*i),10+(35*j),35,35,pMemDC,0,0,SRCCOPY);

}

else if (t[i][j]==dno )

{

pMemDC->SelectObject(pImage[5]);

pDC->BitBlt(10+(35*i),10+(35*j),35,35,pMemDC,0,0,SRCCOPY);

}

else if (t[i][j]==vide )

{

pMemDC->SelectObject(pImage[1]);

pDC->BitBlt(10+(35*i),10+(35*j),35,35,pMemDC,0,0,SRCCOPY);

}

else if (t[i][j]==out )

{

pMemDC->SelectObject(pImage[0]);

pDC->BitBlt(10+(35*i),10+(35*j),35,35,pMemDC,0,0,SRCCOPY);

}

}

 

delete pMemDC;

}

 

// fonction de la gestion du bouton gauche de la souris

void CDamnationView::OnLButtonDown(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

int x,y;

int a,b;

// si le coup est inexistant entre les coordonée, si non la direction

if (!(coupjoueur!=NULL))

{

coupjoueur=cree_coup(point.x/35, point.y/35,NULL,NULL);

xorg=point.x/35;

yorg=point.y/35;

}

else

{

x=point.x/35;

y=point.y/35;

if (x>xorg && y<yorg)

{

a=0;

if (t[x-1][y+1]!=pno)

b=abs(x-xorg);

else

b=abs(x-xorg)-1;

}

else if (x<xorg && y<yorg)

{

a=1;

if (t[x+1][y+1]!=pno)

b=abs(x-xorg);

else

b=abs(x-xorg)-1;

}

else if (x<xorg && y>yorg)

{

a=2;

if (t[x+1][y-1]!=pno)

b=abs(x-xorg);

else

b=abs(x-xorg)-1;

}

else if (x>xorg && y>yorg)

{

a=3;

if (t[x-1][y-1]!=pno)

b=abs(x-xorg);

else

b=abs(x-xorg)-1;

}

if (coupjoueur!=NULL && coupjoueur->dir==NULL)

{

coupjoueur->dir=cree_deplacement(NULL,a+4*(b-1));

xorg=x;

yorg=y;

}

else

{

coupjoueur->dir=ajoute_deplacement_queue(coupjoueur->dir , cree_deplacement(NULL,a+4*(b-1)) );

xorg=x;

yorg=y;

}

}

CFormView::OnLButtonDown(nFlags, point);

}

// gestion du bouton droit de la souris

void CDamnationView::OnRButtonDown(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

pCOUP couppossible; // liste de coup possible

pCOUP lecoupordi; // liste des coup possible pour l'ordi

couppossible=NULL;

lecoupordi=NULL;

 

if (coupjoueur!=NULL)

{

couppossible=list_optimale(t,blanc); // rentre dans couppossible la liste des coups jouables

coupjoueur=recherche(couppossible,coupjoueur); // compare avec le coup du joueur

if (coupjoueur!=NULL)

{

jouer_coup(t,coupjoueur);

coupjoueur=liberation(coupjoueur);

couppossible=liberation(couppossible);

creation_dame(t,blanc);

//SetTimer(1,5,Invalidate()); // gestion du timer ....

Invalidate();

coupjoueur=NULL;

/////////// ORDI TOUR ////////////////////

lecoupordi=list_optimale(t,noir);

lecoupordi=jouer_ordi(t,lecoupordi,noir);

if (lecoupordi!=NULL)

{

jouer_coup(t,lecoupordi);

creation_dame(t,noir);

lecoupordi=liberation(lecoupordi);

Invalidate();

}

else

{

MessageBox("Coup invalide !!! NOIR","Mamamia, une error

...",MB_ICONEXCLAMATION);

}

}

else

{

MessageBox("Coup invalide !!! BLANC","Mamamia, une error

...",MB_ICONEXCLAMATION);

liberation(couppossible);

liberation(coupjoueur);

}

}

else

{

MessageBox("Coup invalide !!!","Mamamia, une error ...",MB_ICONEXCLAMATION);

}

 

CFormView::OnRButtonDown(nFlags, point);

}

 

 

 

//////////////////////////////////////////////////////////////////////

// vide le damier de tout les pions

void CDamnationView::damier_vide(TAB t)

{

int c,l;

for (c=0; c<12 ; c++)

for (l=0; l<12 ; l++)

t[c][l]=out;

for (c=1; c<6 ; c++)

for (l=1; l<6 ; l++)

{

t[2*c][(2*l)-1]=vide;

t[(2*c)-1][2*l]=vide;

}

}

 

/*********************************************************/

// permet de choisir des damiers particulier pour les test

void CDamnationView::damier_particulier(TAB t, int i)

{

switch(i)

{

case 0:

{

damier_vide(t);

break;

}

case 1:

{

damier_vide(t);

//damier_initial(t);

break;

}

case 2:

{

damier_vide(t);

t[5][4]=pno;

t[7][4]=pno;

t[9][4]=pno;

t[7][6]=pno;

t[9][6]=pno;

t[2][9]=pno;

 

t[10][7]=pbl;

t[8][7]=pbl;

t[3][8]=pbl;

break;

}

case 3:

{

damier_vide(t);

t[1][2]=pno;

t[3][4]=pno;

t[5][6]=pno;

t[7][6]=pno;

t[9][6]=pno;

t[9][4]=pno;

t[10][3]=pno;

 

t[6][7]=pbl;

t[10][9]=pbl;

break;

}

case 5:

{

damier_vide(t);

t[2][1]=pno;

t[8][1]=pno;

t[1][2]=pno;

t[4][3]=pno;

t[6][3]=pno;

t[9][4]=pno;

t[10][3]=pno;

t[5][6]=pno;

t[7][6]=pno;

 

/*t[5][4]=pbl; */

t[6][7]=pbl;

t[10][9]=pbl;

break;

}

case 6:

{

damier_vide(t);

t[2][1]=pno;

t[1][2]=pno;

t[4][3]=pno;

t[6][3]=pno;

t[9][4]=pno;

t[3][6]=pno;

t[5][6]=pno;

t[7][6]=pno;

t[1][8]=pno;

 

t[6][7]=pbl;

t[10][9]=pbl;

break;

}

 

case 7:

{

damier_vide(t);

t[9][2]=pno;

t[4][3]=pno;

t[4][5]=pno;

t[6][5]=pno;

t[4][7]=pno;

t[6][7]=pno;

t[8][7]=pno;

t[6][9]=pno;

 

t[8][9]=pbl;

t[5][8]=pbl;

t[8][3]=pbl;

break;

}

 

case 8:

{

damier_vide(t);

t[8][1]=pno;

t[2][3]=pno;

t[6][3]=pno;

t[2][5]=pno;

t[4][5]=pno;

 

t[3][6]=pbl;

 

t[1][10]=pbl;

t[3][10]=pbl;

t[5][10]=pbl;

t[7][10]=pbl;

t[9][10]=pbl;

break;

}

 

 

case 9:

{

damier_vide(t);

t[8][1]=pno;

t[2][1]=pno;

t[2][3]=pno;

t[6][3]=pno;

t[2][5]=pno;

t[4][5]=pno;

 

t[3][6]=pbl;

t[3][4]=pbl;

 

t[1][10]=pbl;

t[3][10]=pbl;

t[5][10]=pbl;

t[7][10]=pbl;

t[9][10]=pbl;

break;

}

 

 

case 10:

{

damier_vide(t);

t[6][5]=pno;

t[8][5]=pno;

t[8][7]=pno;

t[4][9]=pno;

t[6][9]=pno;

 

t[4][3]=pbl;

/*t[8][3]=pbl; */

t[5][4]=pbl;

t[2][5]=pbl;

t[5][6]=pbl;

t[7][6]=pbl;

t[2][7]=pbl;

t[4][7]=pbl;

t[6][7]=pbl;

t[3][8]=pbl;

break;

}

case 11:

{

damier_vide(t);

t[5][2]=pno;

t[4][3]=pno;

t[6][3]=pno;

t[4][5]=pno;

t[6][5]=pno;

 

t[5][6]=pbl;

t[1][4]=pbl;

break;

}

case 12:

{

damier_vide(t);

t[5][2]=pno;

t[4][3]=pno;

t[6][3]=pno;

t[4][5]=pno;

t[6][5]=pno;

 

t[5][6]=pbl;

break;

}

case 13:

{

damier_vide(t);

t[1][10]=pbl;

t[1][2]=pno;

t[3][2]=pno;

t[5][2]=pno;

t[7][2]=pno;

t[9][2]=pno;

 

break;

}

case 14:

{

damier_vide(t);

t[2][1]=pno;

t[3][4]=pno;

t[8][5]=pno;

t[2][5]=pbl;

t[7][6]=pbl;

t[9][6]=pbl;

t[5][8]=pbl;

t[9][8]=pbl;

t[3][10]=pbl;

break;

}

case 15:

{

damier_vide(t);

t[6][3]=pno;

t[10][5]=pno;

//t[2][9]=pno;

t[5][4]=pbl;

t[7][4]=pbl;

t[5][6]=pbl;

t[7][6]=pbl;

t[6][7]=pbl;

t[5][10]=pbl;

t[9][8]=pbl;

t[10][1]=dbl;

t[9][2]=pbl;

 

t[4][9]=pno;

t[2][1]=pno;

//t[10][7]=dno;

break;

}

case 16:

{

damier_vide(t);

t[6][3]=pno;

t[9][4]=pno;

t[2][9]=dno;

t[5][4]=dbl;

t[10][9]=pbl;

t[7][4]=pno;

/* t[5][6]=pbl;

t[7][6]=pbl;

t[6][7]=pbl;

t[3][10]=pbl;

*/ break;

}

case 17:

{

damier_vide(t);

t[7][2]=pno;

t[8][7]=pno;

t[9][2]=pno;

t[5][4]=dbl;

t[10][9]=pbl;

/* t[7][4]=pbl;

t[5][6]=pbl;

t[7][6]=pbl;

t[6][7]=pbl;

t[3][10]=pbl;

*/ break;

}

}}

 

/*********************************************************/

// fonction qui copie un tableau (pas de copie de l'adresse de depart...)

void CDamnationView::copie_tableau(TAB t,TAB ttmp)

{

int c,l;

for (c=0; c<12 ; c++)

for (l=0; l<12 ; l++)

ttmp[c][l]=t[c][l];

}

 

 

/*********************************************************************/

/*****************GESTION DES LISTE *********************************/

/*********************************************************************/

// fonction qui cree un coup

pCOUP CDamnationView::cree_coup(int c, int l, pDEPLACEMENT direction ,pCOUP suivant )

{

pCOUP tmp_coup;

//tmp_coup=(pCOUP)malloc(sizeof(COUP));

tmp_coup=new COUP;

if (tmp_coup == NULL) return NULL;

tmp_coup->x=c;

tmp_coup->y=l;

tmp_coup->suiv=suivant;

tmp_coup->dir=direction;

return tmp_coup;

}

 

/*********************************************************************/

// fonction qui cree un deplacement

pDEPLACEMENT CDamnationView::cree_deplacement(pDEPLACEMENT suivant, int d )

{

pDEPLACEMENT tmp_coup;

//tmp_coup=(pDEPLACEMENT)malloc(sizeof(DEPLACEMENT));

tmp_coup=new DEPLACEMENT;

if (tmp_coup == NULL) return NULL;

tmp_coup->d=d;

tmp_coup->suiv=suivant;

return tmp_coup;

}

 

/*******************************************************************/

// fonction qui ajoute un coup en queue d'une liste de coup

pCOUP CDamnationView::ajoute_coup_queue(pCOUP tete, pCOUP suivant)

{

pCOUP p;

if (tete!=NULL)

{

p=tete;

while (p->suiv!=NULL)

p=p->suiv;

p->suiv=suivant;

}

else

tete=suivant;

return tete;

}

 

 

/********************************************************************/

//fonction qui ajoute un deplacement a la fin d'une liste de deplacement

pDEPLACEMENT CDamnationView::ajoute_deplacement_queue(pDEPLACEMENT tete, pDEPLACEMENT suivant)

{

pDEPLACEMENT p;

if (tete!=NULL)

{

p=tete;

while (p->suiv!=NULL)

p=p->suiv;

p->suiv=suivant;

}

else

tete=suivant;

return tete;

}

 

 

/*********************************************************************/

// fonction qui ajoute un coup en debut d'une liste de coup

pCOUP CDamnationView::ajoute_coup_tete(pCOUP tete, pCOUP new_tete)

{

new_tete->suiv=tete;

return new_tete;

}

 

/*********************************************************************/

// cette fonction suprime le premier coup d'une liste

pCOUP CDamnationView::defiler_coup_tete(pCOUP tete)

{

pCOUP p;

if (tete!=NULL)

{

p=tete->suiv;

while ( tete->dir!=NULL)

{

tete->dir=defiler_deplacement_tete(tete->dir);

}

delete(tete);

}

return p;

}

 

 

/*********************************************************************/

// cette fonction suprime le premier element d'une liste de déplacement

pDEPLACEMENT CDamnationView::defiler_deplacement_tete(pDEPLACEMENT tete)

{

pDEPLACEMENT p=NULL;

if (tete!=NULL)

{

p=tete->suiv;

delete(tete);

}

return p;

}

 

/**********************************************************************/

// cette fonction suprime le dernier element d'une liste de coup

pCOUP CDamnationView::defiler_coup_queue(pCOUP tete)

{

pCOUP q,p=tete;

 

if (tete!=NULL)

{

if (tete->suiv==NULL)

{

tete=defiler_coup_tete(tete);

return NULL;

}

else

{

while (p->suiv!=NULL)

{

q=p;

p=p->suiv;

}

q->suiv=NULL;

p=defiler_coup_tete(p);

}

}

return tete;

}

 

/****************************************************************************/

// cette fonction supprime le dernier element d'une liste de déplacement

pDEPLACEMENT CDamnationView::defiler_deplacement_queue(pDEPLACEMENT tete)

{

pDEPLACEMENT q,p=tete;

 

if (tete!=NULL)

{

if (tete->suiv==NULL)

{

delete(tete);

return NULL;

}

else

{

while (p->suiv!=NULL)

{

q=p;

p=p->suiv;

}

q->suiv=NULL;

delete(p);

}

}

return tete;

}

 

 

 

/*************************************************************************/

/* recherche le maillon tete dans dans la liste

renvoie la tete si trouver sinon renvoi NULL*/

 

pCOUP CDamnationView::recherche(pCOUP list, pCOUP tete)

{

pDEPLACEMENT p,t;

if (list==NULL) return NULL;

if (list->x==tete->x && list->y==tete->y)

{

if (list->dir!=NULL && tete->dir!=NULL)

{

p=list->dir;

t=tete->dir;

while (p!=NULL || t!=NULL)

{

if (p->d==t->d)

{

p=p->suiv;

t=t->suiv;

}

else

return recherche (list->suiv, tete);

}

if ( p==NULL && t==NULL ) return tete;

}

return recherche (list->suiv, tete);

}

return recherche (list->suiv, tete);

 

}

 

/*******************************************************************************/

// cette fonction fais une copie d'une liste de déplacement, c'est une copie réelle

pDEPLACEMENT CDamnationView::copie_list_deplacement(pDEPLACEMENT p)

{

pDEPLACEMENT ntete=NULL;

pDEPLACEMENT tmp=NULL;

 

while (p!=NULL)

{

tmp=cree_deplacement(NULL,p->d);

ntete=ajoute_deplacement_queue(ntete,tmp);

p=p->suiv;

}

return ntete;

}

/**************************************************************************/

// cette fonction copie une liste de coup , c'est une copie réelle

pCOUP CDamnationView::copie_list_coup(pCOUP tete)

{

 

pCOUP ntete=NULL;

pCOUP p=tete;

pCOUP tmp=NULL;

while (p!=NULL)

{

tmp=cree_coup(p->x,p->y,copie_list_deplacement(p->dir),NULL);

ntete=ajoute_coup_queue(ntete,tmp);

p=p->suiv;

}

return ntete;

}

 

/********************************************************************/

// cette fonction renvoie le nombre maximum de deplacement pour un coup, dans une liste de coup

int CDamnationView::compter_deplacement(pCOUP tete)

{

int x=0;

pDEPLACEMENT p;

if (tete==NULL)

{

return 0;

}

else

{

p=tete->dir;

while (p!=NULL)

{

p=p->suiv;

x++;

}

}

return x;

}

 

 

/*****************************************************************************/

/* renvoie une liste dont les deplacements sont >= max */

pCOUP CDamnationView::meilleur_coup_dune_list(pCOUP tete, int max)

{

pCOUP p;

if (tete!=NULL)

{

p=tete;

while (p->suiv!=NULL)

{

if (compter_deplacement(p->suiv)<max)

{

p->suiv=defiler_coup_tete(p->suiv) ;

}

else

p=p->suiv;

}

if ( (tete->dir==NULL) || (compter_deplacement(tete)<max) )

tete=defiler_coup_tete(tete); /* la non plus !!!!! */

}

return tete;

}

 

 

 

 

/*********************************************************************/

/*********************************************************************/

// cette fonction permet de deplacer un pion dans une direction (gere si il faut manger) et suprime le deplacement d'une liste deplacement

pCOUP CDamnationView::jouer_direction(TAB damier, pCOUP tete)

{

int a,k,x,y,couleur,dx,dy;

pDEPLACEMENT p;

 

if (tete!=NULL && tete->dir !=NULL )

{

k=(tete->dir)->d;

x=tete->x;

y=tete->y;

couleur=damier[x][y]/abs(damier[x][y]);

a=(k/4)+1; /* donne l'amplitude */

k=k%4; /* donne la direction */

dx=a*d[k].x*couleur;

dy=a*d[k].y*couleur;

 

if (damier[tete->x+dx][tete->y+dy]*damier[tete->x][tete->y]<0)

{

damier[tete->x+dx][tete->y+dy]=vide;/* on prend un pion adverse */

dx=dx+d[k].x*couleur; /* a modifier pour la dame */

dy=dy+d[k].y*couleur;

}

 

damier[x+dx][y+dy]=damier[tete->x][tete->y]; /* position finale */

damier[x][y]=vide; /* position initiale vide */

p=defiler_deplacement_tete(tete->dir);

 

tete->dir=p;

tete->x=x+dx;

tete->y=y+dy;

return tete;

}

else

return NULL;

}

 

/*******************************************************************************/

// cette fonction apelle la fonction precedente pour jouer un coup complet (x,y,{directions}), elle ne suprime pas le coup!

pCOUP CDamnationView::jouer_coup(TAB damier, pCOUP tete)

{

pCOUP p=tete; /* perte de l'information */

pCOUP q=tete->suiv;

 

while (p->dir != NULL)

{

p=jouer_direction(damier,p);

}

 

return q;

}

 

/*********************************************************************/

// cette fonction retourne la complexite du damier...

/* renvoie 0 si prise

1 si deplacement simple

2 si fin de partie */

int CDamnationView::test_complexite(TAB t, int couleur )

{

int c,l,i,k,a,b,cdx,cdy,cdx2,cdy2,test,j=2;

for (c=1; c<11; c++)

for (l=1; l<11; l++) /* toutes les cases */

{

if (( t[c][l]==couleur || t[c][l]==2*couleur ) ) /* de la bonne couleur */

{

for (k=0;k<35;k++)

{

a=(k/4)+1;

b=k%4;

if (t[c][l]==couleur && k>=4)

/* si c'est un pion et amplitude sup a 1 */

{

k=35; /* sort du for */

}

else

{

cdx=c+(a*d[b].x)*couleur;

cdy=l+(a*d[b].y)*couleur;

if ( (cdx>0) &&

(cdx<11) &&

(cdy >0) &&

(cdy <11) )

{

if (t[cdx][cdy]==-couleur || t[cdx][cdy]==-2*couleur )

{

if (t[cdx+couleur*d[b].x][cdy+couleur*d[b].y]==vide)

{

test=0;

for (i=1;i<a;i++)

{

cdx2=c+(i*d[b].x)*couleur;

cdy2=l+(i*d[b].y)*couleur;

if (t[cdx2][cdy2]!=vide) test=1;

/* la diagonale est pleine */

}

if (test==0)

{

return complexe;

}

}

}

else if (t[cdx][cdy]==vide )

{

test=0;

for (i=1;i<a;i++)

{

cdx2=c+(i*d[b].x)*couleur;

cdy2=l+(i*d[b].y)*couleur;

if (t[cdx2][cdy2]!=vide) test=1; /* la diagonale est pleine */

}

if (test==0)

{

if (abs(t[c][l])==1 && k==0 ||

abs(t[c][l])==1 && k==1 ||

abs(t[c][l])==2 )

{

j=simple;

}

}

}

}

}

}

}

}

return j;

}

 

 

/*************************************************************************************/

/* cree une liste de deplacement a partir d'une colonne, ligne ,couleur de la complexite

exp : si case blanche deplacable droite et gauche (0.1.FIN)

envisager le meme type de procedure pour la dame */

pDEPLACEMENT CDamnationView::test_deplacement(TAB t, int c, int l ,int couleur, int test_simple)

{

pDEPLACEMENT p;

pDEPLACEMENT tete=NULL;

int i,k,a,b,cdx,cdy,cdx2,cdy2,test;

 

if (( t[c][l]==couleur || t[c][l]==2*couleur ) ) /* de la bonne couleur */

{

for (k=0;k<35;k++)

{

a=(k/4)+1;

b=k%4;

if (t[c][l]==couleur && k>=4) /* si c'est un pion et amplitude sup a 1 */

{

k=35; /* sort du for */

}

else

{

cdx=c+(a*d[b].x)*couleur;

cdy=l+(a*d[b].y)*couleur;

if ( (cdx>0) && (cdx<11) && (cdy >0) && (cdy <11) )

{

if ( (t[cdx][cdy]==-couleur || t[cdx][cdy]==-2*couleur ))

{

if (t[cdx+couleur*d[b].x][cdy+couleur*d[b].y]==vide)

{

test=0;

for (i=1;i<a;i++) {

cdx2=c+(i*d[b].x)*couleur; cdy2=l+(i*d[b].y)*couleur;

if (t[cdx2][cdy2]!=vide) test=1;

/* la diagonale est pleine */

}

if (test==0)

{

p=cree_deplacement(NULL,k);

tete=ajoute_deplacement_queue(tete,p);

}

}

}

else

if (test_simple==simple && t[cdx][cdy]==vide)

{

test=0;

for (i=1;i<a;i++)

{

cdx2=c+(i*d[b].x)*couleur;

cdy2=l+(i*d[b].y)*couleur;

if (t[cdx2][cdy2]!=vide) test=1; /* la diagonale est pleine */

}

if (test==0)

if ((abs(t[c][l])==2) ||

((abs(t[c][l])==1) && ( (k==0) || (k==1) ) ) )

{

p=cree_deplacement(NULL,k);

tete=ajoute_deplacement_queue(tete,p);

}

}

}

 

}

}

}

return tete;

}

 

/************************************************************************************/

// cette fonction renvoie a partir d'un tableau la liste des pions que l'on peu deplacer.

pCOUP CDamnationView::list_pion_jouable(TAB t, int couleur )

{

int l,c,comp; /******/

pDEPLACEMENT k;

pCOUP tmp_coup;

pCOUP tete=NULL;

 

comp=test_complexite(t,couleur);

for (l=1;l<11;l++)

for (c=1;c<11;c++)

{

if ((t[c][l]==couleur) || (t[c][l]==2*couleur))

{

k=test_deplacement(t,c,l,couleur,comp); /* !!!!!!!!!!!!! simple */

if (k!=NULL)

{

tmp_coup=cree_coup(c,l,k,NULL);

/* premer nul a remplacer par la liste des deplacement */

tete=ajoute_coup_queue(tete,tmp_coup);

}

}

}

return tete;/* parcourir le damier et faire les tests de bases sur chaque pions trouves */

}

 

/*************************************************************************/

/* renvoie le plus grand nombre de deplacement possible

cree les listes de coup

exp (2,4){1.2.1.2.FIN} c'est un coup de 4 deplacements 4 pions manges */

 

int CDamnationView::trouver_coup(TAB t,pCOUP tete, int profondeur, int complexite)

{

 

int copie_profondeur;

pDEPLACEMENT deptmp,copie_direction,q;

pCOUP tetetmp,copie_tete,p;

TAB ttmp;

copie_tableau(t,ttmp);

if (tete->dir!=NULL)

copie_direction=copie_list_deplacement((tete->dir)->suiv);

/* les directions moins la premiere */

 

copie_tete=cree_coup(tete->x,tete->y,copie_direction,tete->suiv);

copie_profondeur=profondeur;

 

if (tete->dir!=NULL)

{

/* on sauve les deplacements dans depl_trouver */

q=cree_deplacement(NULL,(tete->dir)->d);

depl_trouver=ajoute_deplacement_queue(depl_trouver,q);

/* modification du damier ttmp et modification de la tete des coups */

tetetmp=jouer_direction(ttmp,tete);

/* effacer les deplacements anterieur issus des coup possible */

while (tetetmp->dir !=NULL)

{

tetetmp->dir=defiler_deplacement_tete(tetetmp->dir);

}

 

/* s'il ne sagit pas de prise avec coup il n'y a pas de coup suivant */

if (complexite==complexe)

{

/* creation de la liste des deplacements pour cette nouvelle tete */

deptmp=test_deplacement(ttmp,tetetmp->x,tetetmp->y,t[copie_tete- >x][copie_tete->y]/abs(t[copie_tete->x][copie_tete->y]),complexe);

tetetmp->dir=deptmp;

}

else

{

profondeur-=1; /* cad aucun pion de pris */

}

/* premier appel recurssif sur le nouveau damier avec la nv tete */

trouver_coup(ttmp,tetetmp,++profondeur,complexite);

 

 

/* sauvegarder la liste des deplacements arrivant a un bout

dans une liste de coup */

p=cree_coup(coup_trouver->x,coup_trouver- >y,copie_list_deplacement(depl_trouver),NULL);

coup_trouver=ajoute_coup_queue(coup_trouver,p);

 

 

/* backtracking sur la liste des deplacements c'est les meme

deplacement moins le dernier */

depl_trouver=defiler_deplacement_queue(depl_trouver);

 

/* calcul de la profondeur max */

if (profondeur>prof_max) prof_max=profondeur;

copie_tableau(t,ttmp);

 

 

/* etude de la liste des deplacements ( representation d'un arbre n ere */

if (copie_tete->dir!=NULL)

{

/* deuxieme appel recurssif pour effectuer tout les deplacements maxi 4 */

trouver_coup(ttmp,copie_tete,copie_profondeur,complexite);

free(copie_tete);

}

}

return prof_max;

}

 

 

 

/*************************************************************************************/

// renvoie la liste des coup possible en fonction d'untableau et d'une couleur. Il renvoie donc les pions que l'on peut deplacer et qui doivent manger un maximum de pion.

pCOUP CDamnationView::list_optimale(TAB t,int couleur)

{

int complexite,nbrc=0,max_du_plateau=0;

pCOUP toto=NULL,p=NULL;

complexite=1;

complexite=test_complexite(t,couleur);

if (complexite!=2) /* 2 aucune case de la couleur est jouable */

{

toto=list_pion_jouable(t,couleur);

coup_trouver=cree_coup(toto->x,toto->y,NULL,NULL);

while (toto!=NULL)

{

coup_trouver->x=toto->x;

coup_trouver->y=toto->y;

nbrc=trouver_coup(t,toto,0,complexite);

if (nbrc>max_du_plateau)

{

max_du_plateau=nbrc;

}

 

 

/* defiler la liste principale */

p=toto;

 

toto=toto->suiv;

while (p->dir!=NULL)

{

p->dir=defiler_deplacement_tete(p->dir);

}

delete(p); /* supprimer les direction */

}

coup_trouver=meilleur_coup_dune_list(coup_trouver,max_du_plateau);

}

else

{

//printf("Une issue de la partie atteinte");

coup_trouver=NULL; /* penser a supprimer l'assert ds la fct complexi.. */

}

 

return coup_trouver;

}

 

 

/********************************************************************************/

// cette fonction libere la memoire de la liste coup et remet le pointeur a NULL

pCOUP CDamnationView::liberation( pCOUP tete)

{

while (tete!=NULL)

tete=defiler_coup_tete(tete);

return NULL;

}

 

 

 

/*****************************************************************************/

// cette fonction retourne la valeur d'un tableau en fonction de la diferrence de pion

int CDamnationView::score_tableau(TAB t)

{

int i,j,pion_blanc=0,pion_noir=0;

for (i=1;i<11;i++)

for (j=1; j<11;j++)

{

if (t[i][j]==pbl || t[i][j]==dbl) pion_blanc+=1;

if (t[i][j]==pno||t[i][j]==dno) pion_noir+=1;

}

return (pion_noir-pion_blanc);

 

}

 

 

 

/*******************************************/

/* ressort le meilleur coup a jouer parmis une liste qui ammene

la meme prise de pions

rappel: on est obliger de prendre le max de pions sinon il faut modifier

la fct qui supprime si inf a max */

int CDamnationView::meilleur_coup(TAB t, pCOUP tete,int couleur, int profondeur)

{

pCOUP p2=NULL;

TAB ttmp;

int la_valeur,valeur;

 

if (profondeur_max==profondeur)

{

return score_tableau(t);

}

else

{

if (profondeur%2)

la_valeur=100;

else

la_valeur=-100;

while (tete!=NULL)

{

prof_max=0;

copie_tableau(t,ttmp);

tete=jouer_coup(ttmp,tete);

creation_dame(ttmp,couleur);

p2=copie_list_coup(list_optimale(ttmp,-couleur));

valeur=meilleur_coup(ttmp,p2,-couleur,profondeur+1);

p2=liberation(p2);

if (profondeur%2)

{

if (la_valeur>valeur) la_valeur=valeur;

}

else

{

if (la_valeur<valeur) la_valeur=valeur;

}

}

return la_valeur;

}

}

 

/*****************************************************************************/

// cette fonction etabli le meilleur coup pour l'ordinateur en corelation avec la precedente

pCOUP CDamnationView::jouer_ordi(TAB t, pCOUP liste, int couleur)

{

pCOUP un_coup,le_coup,coupbis;

pDEPLACEMENT un_deplacement;

TAB ttmp;

int val;

 

le_coup=NULL;

if (couleur==blanc) max=100;

else max=-100;

 

while(liste != NULL)

{

un_deplacement=copie_list_deplacement(liste->dir);

un_coup=cree_coup(liste->x,liste->y,un_deplacement,NULL);

liste=defiler_coup_tete(liste);

copie_tableau(t,ttmp);

coupbis=copie_list_coup(un_coup);

val=meilleur_coup(ttmp,un_coup,couleur,0);

un_coup=liberation(un_coup);

if (couleur==blanc)

{

if (val<max)

{

max=val;

le_coup=liberation(le_coup);

le_coup=coupbis;

}

}

else

if (val>max)

{

max=val;

le_coup=liberation(le_coup);

le_coup=coupbis;

}

 

 

}

return(le_coup);

}

 

 

 

 

/***************************************************************************/

// cette fonction verifie si la partie est finie

int CDamnationView::test_victoire (TAB t)

{

int i,j;

int bl=0;

int no=0;

for (i=1; i<11; i++)

for (j=1; j<11; j++)

{

if( t[i][j]>0 ) bl=bl+t[i][j];

if( t[i][j]<0 ) no=no+t[i][j];

}

bl=bl-(50*out);

if (bl+no<0)

MessageBox("Les noirs gagnent","FIN",MB_ICONSTOP);

else

MessageBox("Les blancs gagnent","FIN",MB_ICONSTOP);

return (bl+no);

}

 

 

 

/*******************************************************************************/

// cette fonction verifie si un pion est en position d'être une dame et le transforme si c'est le cas.

void CDamnationView::creation_dame(TAB t,int couleur)

{

int k,i;

if (couleur==1) k=1;

else k=10;

for (i=1;i<11; i++)

if (t[i][k]==couleur) t[i][k]=2*couleur;

 

}

 

 

 

 

 

////////////////////////////////////////////////////////////

// cette fonction permet un affichage d'une liste de coup (sert uniquement pour le debugage)

void CDamnationView::afficher_list_coup(pCOUP tete)

{

pCOUP p=NULL;

p=tete;

 

int i;

 

char txt[20],tmp[20];

 

if ( tete!=NULL )

{

 

while ( p != NULL )

{

tmp[0]=(char)(p->x+'0');

tmp[1]='-';

tmp[2]=(char)(p->y+'0');

tmp[3]='(';

i=4;

while (p->dir != NULL)

{

tmp[i++]=(char)(p->dir->d + '0');

tmp[i++]=' ';

p->dir=p->dir->suiv;

}

tmp[i++]=')';

MessageBox(tmp," ",MB_OK);

p=p->suiv;

}

}

else

MessageBox("Pas de coup possible.... :)))"," ",MB_OK);

}

 

 

// gestion du changement de profondeur sur appuie du bouton 1 2 ou 3

void CDamnationView::OnButton1()

{

// TODO: Add your command handler code here

profondeur_max=2;

}

 

void CDamnationView::OnButton2()

{

// TODO: Add your command handler code here

profondeur_max=3;

}

 

void CDamnationView::OnButton3()

{

// TODO: Add your command handler code here

profondeur_max=4;

}

 

// fonction timer qui devrais permettre de lancer le reaffichage de l'ecran en tache de fond...

void CDamnationView::OnTimer(UINT nIDEvent)

{

// TODO: Add your message handler code here and/or call default

Invalidate();

KillTimer(1);

 

 

CFormView::OnTimer(nIDEvent);

}

 

C. DamnationDoc.h

// DamnationDoc.h : interface of the CDamnationDoc class

//

/////////////////////////////////////////////////////////////////////////////

 

class CDamnationDoc : public CDocument

{

protected: // create from serialization only

CDamnationDoc();

DECLARE_DYNCREATE(CDamnationDoc)

 

// Attributes

public:

 

// Operations

public:

 

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CDamnationDoc)

public:

virtual BOOL OnNewDocument();

virtual void Serialize(CArchive& ar);

//}}AFX_VIRTUAL

 

// Implementation

public:

virtual ~CDamnationDoc();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

 

// Generated message map functions

protected:

//{{AFX_MSG(CDamnationDoc)

// NOTE - the ClassWizard will add and remove member functions here.

// DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

 

/////////////////////////////////////////////////////////////////////////////

 

D. DamnationDoc.cpp

// DamnationDoc.cpp : implementation of the CDamnationDoc class

//

 

#include "stdafx.h"

#include "Damnation.h"

 

#include "DamnationDoc.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationDoc

 

IMPLEMENT_DYNCREATE(CDamnationDoc, CDocument)

 

BEGIN_MESSAGE_MAP(CDamnationDoc, CDocument)

//{{AFX_MSG_MAP(CDamnationDoc)

// NOTE - the ClassWizard will add and remove mapping macros here.

// DO NOT EDIT what you see in these blocks of generated code!

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationDoc construction/destruction

 

CDamnationDoc::CDamnationDoc()

{

// TODO: add one-time construction code here

 

}

 

CDamnationDoc::~CDamnationDoc()

{

}

 

BOOL CDamnationDoc::OnNewDocument()

{

if (!CDocument::OnNewDocument())

return FALSE;

 

// TODO: add reinitialization code here

// (SDI documents will reuse this document)

 

return TRUE;

}

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationDoc serialization

 

void CDamnationDoc::Serialize(CArchive& ar)

{

if (ar.IsStoring())

{

// TODO: add storing code here

}

else

{

// TODO: add loading code here

}

}

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationDoc diagnostics

 

#ifdef _DEBUG

void CDamnationDoc::AssertValid() const

{

CDocument::AssertValid();

}

 

void CDamnationDoc::Dump(CDumpContext& dc) const

{

CDocument::Dump(dc);

}

#endif //_DEBUG

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationDoc commands

 

E. Damnation.h

// Damnation.h : main header file for the DAMNATION application

//

 

#ifndef __AFXWIN_H__

#error include 'stdafx.h' before including this file for PCH

#endif

 

#include "resource.h" // main symbols

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationApp:

// See Damnation.cpp for the implementation of this class

//

 

class CDamnationApp : public CWinApp

{

public:

virtual BOOL PreTranslateMessage(MSG* pMsg);

CDamnationApp();

 

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CDamnationApp)

public:

virtual BOOL InitInstance();

//}}AFX_VIRTUAL

 

// Implementation

 

//{{AFX_MSG(CDamnationApp)

afx_msg void OnAppAbout();

// NOTE - the ClassWizard will add and remove member functions here.

// DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

 

 

/////////////////////////////////////////////////////////////////////////////

 

F. Damnation.cpp

// Damnation.cpp : Defines the class behaviors for the application.

//

 

#include "stdafx.h"

#include "Damnation.h"

 

#include "MainFrm.h"

#include "DamnationDoc.h"

#include "DamnationView.h"

#include "Splash.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationApp

 

BEGIN_MESSAGE_MAP(CDamnationApp, CWinApp)

//{{AFX_MSG_MAP(CDamnationApp)

ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

// NOTE - the ClassWizard will add and remove mapping macros here.

// DO NOT EDIT what you see in these blocks of generated code!

//}}AFX_MSG_MAP

// Standard file based document commands

ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)

ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationApp construction

 

CDamnationApp::CDamnationApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance

}

 

/////////////////////////////////////////////////////////////////////////////

// The one and only CDamnationApp object

 

CDamnationApp theApp;

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationApp initialization

 

BOOL CDamnationApp::InitInstance()

{

// CG: The following block was added by the Splash Screen component.

{

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

 

CSplashWnd::EnableSplashScreen(cmdInfo.m_bShowSplash);

}

// Standard initialization

// If you are not using these features and wish to reduce the size

// of your final executable, you should remove from the following

// the specific initialization routines you do not need.

 

#ifdef _AFXDLL

Enable3dControls(); // Call this when using MFC in a shared DLL

#else

Enable3dControlsStatic(); // Call this when linking to MFC statically

#endif

 

LoadStdProfileSettings(0); // Load standard INI file options (including MRU)

 

// Register the application's document templates. Document templates

// serve as the connection between documents, frame windows and views.

 

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CDamnationDoc),

RUNTIME_CLASS(CMainFrame), // main SDI frame window

RUNTIME_CLASS(CDamnationView));

AddDocTemplate(pDocTemplate);

 

// Parse command line for standard shell commands, DDE, file open

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

 

// Dispatch commands specified on the command line

if (!ProcessShellCommand(cmdInfo))

return FALSE;

 

return TRUE;

}

 

/////////////////////////////////////////////////////////////////////////////

// CAboutDlg dialog used for App About

 

class CAboutDlg : public CDialog

{

public:

CAboutDlg();

 

// Dialog Data

//{{AFX_DATA(CAboutDlg)

enum { IDD = IDD_ABOUTBOX };

//}}AFX_DATA

 

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CAboutDlg)

protected:

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

//}}AFX_VIRTUAL

 

// Implementation

protected:

//{{AFX_MSG(CAboutDlg)

// No message handlers

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

 

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)

{

//{{AFX_DATA_INIT(CAboutDlg)

//}}AFX_DATA_INIT

}

 

void CAboutDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CAboutDlg)

//}}AFX_DATA_MAP

}

 

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)

//{{AFX_MSG_MAP(CAboutDlg)

// No message handlers

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

// App command to run the dialog

void CDamnationApp::OnAppAbout()

{

CAboutDlg aboutDlg;

aboutDlg.DoModal();

}

 

/////////////////////////////////////////////////////////////////////////////

// CDamnationApp commands

 

BOOL CDamnationApp::PreTranslateMessage(MSG* pMsg)

{

// CG: The following lines were added by the Splash Screen component.

if (CSplashWnd::PreTranslateAppMessage(pMsg))

return TRUE;

 

return CWinApp::PreTranslateMessage(pMsg);

}