Citation du moment : Progrès.

"Le but de la société humaine doit être le progrès des hommes, non celui des choses." Léonard Sismonde de Sismondi

 

Bataille navale

Voici un petit programme/jeu de bataille navale que j’ai réalisé avec des camarades de classe pendant nos études, daté de 1999. Il est écrit en C, et a une interface en texte.

Projet

En fin d’année 1999, nous avons eu des mini-projets à réaliser en informatique. Ce pouvait-être du calcul numérique applique à la micro-électronique (super réseaux...) ou de la programmation. Le sujet tiré au sort par mon groupe fut la bataille navalle.

Code source bataille navale

Je partage le fruit de ce projet sur internet, il peut donc bien sûr servir de base à des projets/TPet TD d’étudiants. Mais j’éncourage à réutiliser et compléter le programme plutôt que le recopier, et je ne travaillerai pas à la place des étudiants (ce qui m’a déjà été demandé).

But du programme

Le but du programme est de réaliser une bataille navalle, programmée en C. Rien n’est imposé, les rêgles du jeu sont libres, etc., il doit cependant être possible de jouer contre l’ordinateur.

Modélisation du problème

1. Rêgles du jeu retenues

Nous avons décidé d’utiliser les rêgles classiques, ce qui fut un peu reproché. Il y a deux joueurs, les bateaux sont disposés horizontalement ou verticalement, sur une grille de 10x10 (lettres à la verticales, chiffres à l’horizontale). Il y a 6 bateaux :

- 1 porte-avions, 5 cases
- 1 destroyer, 4 cases
- 2 frégates, 3 cases
- 2 sous-marins, 2 cases

Les joueurs jouent à tour de role, en demandant une case à chaque fois. Les résultats sont "A l’eau", "Touché" et "Coulé".

2.Que le programme devait-il faire ?

Il a alors définir les taches de chacun, car nous étions 4, et ce que devait faire le programme. Voici en vrac ce que cela a donné :

- jouer à deux joueurs humains
- joueur seul contre l’ordinateur
- regarder jouer l’ordinateur tout seul
- réaliser l’affichage
- mettre en place les bateaux (manuellement ou automatiquement)
- faire jouer les joueurs
- détecter le resultat des tirs
- couler les bateaux
- pour les joueurs humains, il faut réaliser une procédure demandant les coordonnées
- pour l’ordinateur, il faut réaliser les procédures de jeu automatique

Faire jouer l’ordinateur, niveaux de jeu de l’ordinateur

Nous avons décidé de créer plusieurs niveaux de jeu, car en plus, tout ne pouvait pas etre écrit d’une seule fois. En faisant d’abord les bases et en enchérissant, cela crée finalement des niveaux.

- Niveau 0 : l’ordinateur joue complètement aléatoirement, et peut donc tirer deux fois au même endroit.

- Niveau 1 : les tirs sont aléatoires, mais lorsqu’il touche l’un des bateaux, il tire juste a coté de ce point (horizontalement ou verticalement).Quand il le touche de nouveau, il continue à tirer dans la même direction jusqu’à ce qu’il soit coulé. Il ne peut pas tirer au même endroit dans ce niveau de jeu, et il ne tire pas non plus a coté d’un bateau coulé.
- Niveau 2 : l’ordinateur a les mêmes possibilités que pour le niveau précédent avec quelques améliorations dans sa tactique de jeu. Il évalue la place disponible autour d’une case, et suivant la dimension des bateaux restants, il verra s’il y a la place d’en placer un. Si ce n’est pas le cas, il éliminera ces cases de son champ de tir.

Coté programmation

Le programme a donc été réalisé en C (et sera donc bien moins lisible qu’un programme en PASCAL pour les novices), sous un environnement Solaris, par des personnes a qui on n’a jamais montre comment on pouvait programmer sous l’interface graphique sous cet environnement. C’est donc la console (mode texte) qui a été utilisée. Cela a le mérite d’etre valide pour l’environnement PC, et ce, sans modifications.

Voici la partie déclarations du programme, pour avoir une petite idée.

/* DELROT Pascal - MEA1                                              12/V/99 */
/*                                Informatique                               */
/*---------------------------------------------------------------------------*/
/* avec DRUILHE Emily, DAVID Mathieu, DELAITRE Antoine */

/*  Bataille navale   */

/* >> Pb connu : P en G1h, chez ordinateur 1 : touche=G1 G2, décide de jouer en G3 "On va tirer" puis bloque (ne va pas à "Ordinateur fin" !!!) */
/* Pour le joueur 2, l'ordinateur 1 coule très bien ce meme bateau */

/* >> Les coups doubles sont comptés */

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include <stdio.h>
#include <time.h>
/*#include <curses.h>*/
/*#include "/U/delrot/prog-c/include/num.c"*/
/*#include "/U/delrot/prog-c/include/chaines.c"*/

/*****************************************************************************/
/* En provenance de mes bibliothèques */
#define SUP(a,b)  ( (a>=b) ? a : b )
#define INF(a,b)  ( (a<=b) ? a : b )
#define ENTRE(a,x,b)  ( (x>=a) && (x<=b) )
#define UpCase(c) ( ( (c>='a') && (c<='z') ) ? ( c+'A'-'a' ) : c )

/* Renvoie un nombre entre 0 et max */
#define RANDOM(max) ( max*rand()*1.0/((1<<15)-1) )
#define iRANDOM(max) ( (int)(RANDOM(max)) )

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Constantes */
#define M 10 /* Jusqu'à 20 */
#define N 10 /* Jusqu'à 20 */
#define N_Joueurs   2
#define TabTirs     1
#define TabBateaux  2

/* Types de cases : Tirs */
/* PasPossible est utilisé pour marquer les cases où il ne peut pas y avoir de bateaux */
#define CaseVide    ' '
#define Touche     '*'  /*'×'*/
#define Coule      '#'
#define Aleau      'o'
#define PasPossible 'ø'

/* Bateaux : mis dans Bateaux */
/* Porte-avions= 5; Destroyer= 4; Frégates=3; sous-marins= 2 */
/* 10x10 : 1 porte-avions; 1 destroyer; 2 frégates; 2 sous-marins */
/* 20x20 et plus 3, 2, 3, 2 */
#define PorteAvions 'P'
#define Destroyer   'D'
#define Fregate     'F'
#define SousMarin   'S'

typedef struct {int X;int Y;} TPoint;  /* Structure point */

char Bateaux[N_Joueurs][M][N]; /* Emplacement des bateaux */
char Tirs[N_Joueurs][M][N];   /* Emplacement des tirs */
TPoint Boom[N_Joueurs];       /* Dernier tir des joueurs si Touche -> Ordinateur */
int BateauTouche[N_Joueurs];  /* Vrai si un bateau est touche */
int BateauxCoules[N_Joueurs][4]= { {1,1,2,2},{1,1,2,2} };  /* Nombre de bateaux disponibles P D F S */

int Coups[N_Joueurs]= {0,0}; /* Nombre de coups joues -> Stratégie du PC */

/* Genre des joueurs et leurs choix */
#define Humain  1
#define Machine 2      /* Valeur réelle = Machine+niveau */
int TypeJoueur[N_Joueurs];
char NomJoueur[N_Joueurs][13];
int PlaceAuto[N_Joueurs];

int Joueur=0;  /* Le joueur qui est en train de jouer */

/*****************************************************************************/
/* Procédures des bibliotheques */
char AttendTouche(char);      /* Est censée attendre la touche donnée */
char *XCar(char, int, char*);  /* Renvoie dans s nbr caractères c identiques */

/*****************************************************************************/
#define EstChiffre( c ) ( ENTRE('0', c, '9') )
#define EstLettre( c )  ( ENTRE('a', c, 'z') || ENTRE('A', c, 'Z') )

/* Donnent un chiffre et un nombre */
#define char2int( c ) ( c-'0')
int str2int(char*);

/*****************************************************************************/
/* Procédures propres au jeu */
#define AutreJoueur(j) ( (j+1)%N_Joueurs )
#define Gagne(qui) ( !BateauxCoules[qui][0] && !BateauxCoules[qui][1] && !BateauxCoules[qui][2] && !BateauxCoules[qui][3] )

void Initialisation();        /* Tout à 0 */
void Parametres();            /* Joueurs, mise en place */
void AfficheChiffres();       /* Affiche une ligne de chiffres (sans entree) */
void AfficheTableau(int);     /* Affiche les deux tableaux du joueur */
void Affichage(int, TPoint*); /* Fait la mise en page */
TPoint Coordonnees();         /* Demande des coordonnées */

void MisePlace(int, int);     /* Pour mettre les bateaux */
void Placement(int, int , int);  /* Placement manuel ou automatique */

void Jouer();                 /* Boucle principale */
int ToucheCoule(TPoint);      /* Le bateau est-il coulé ? */
int CouleLe(TPoint);          /* Coule le bateau */
int TailleMin(int);           /* Taille du plus petit bateau non coule */
char SensBateau(TPoint);      /* Donne le sens du bateau */<

TPoint JoueurAuto();          /* Fait jouer l'ordinateur */
TPoint ChercheVide();         /* Cherche un case vide pour 'Joueur' */
TPoint TireACote();           /* Joue sur les bateaux touchés */
TPoint Niveau0();             /* Jeu aléatoire */
TPoint Niveau1();             /* Jeu intermédiaire */
TPoint Niveau2();             /* Bon, tire que là où il y a de la place */

Toutes les fonctions ont été construites autour de la fonction "Jouer". Celle-ci attend les coordonnées des tirs des joueurs et seulement cela (peu importe le type de joueur et où il se trouve). La détermination du résultat se fait ensuite avec "ToucheCoule". La fonction "CouleLe" permet de couler les bateaux.

Le joueur humain est représenté par "Coordonnées" et l’ordinateur par "JoueurAuto". Cette fonction sert d’aiguillage vers les différents niveaux de jeu de l’ordinateur.

Les niveaux de jeu de l’ordinateur ont été organisés par couches, chaque couche supérieure ajoutant un degré de finesse aux couches du bas, aux actions correctes et déterminées (similaire au principe de surcharge d’objets programmation objet).

Les fonctions jouant ce rôle sont "Niveau0", "Niveau1" et "Niveau2". Cependant elles ne font pas tout toutes seules, car sinon le programme aurait été illisible. Certaines fonctionnalités ont été mises dans des fonctions à part. C’est le cas de "TireACote" qui tire à coté (!) des bateaux lorsqu’on en connaît la direction. "SensBateau" donne le sens des bateaux, si c’est possible et "TailleMin" donne la taille du plus petit bateau restant à couler.

Cette dernière fonction permet de savoir s’il y a la place de placer un bateau et test utilisée pour une légère optimisation des tirs de "Niveau2" qui ne se contente pas de tirer uniquement là où c’est possible. On tire en fait en laissant un nombre de cases juste suffisant dans l’espace vide pour qu’il ne puisse pas y avoir de bateau (si il ne reste que des frégates à couler, laisser 2 cases vides les élimine toutes les deux, car elles ne forment pas un espace assez grand).

Pour la rédaction du programme le plus ennuyeux à faire ont été les boucles car il n’y a pas que les limites des tableaux à vérifier. Les conditions en deviennent vite très longues et peu lisibles. D’autre par il a souvent fallu distinguer les cas verticaux et horizontaux, bien qu’il y ait très peu de différence entre les boucles écrites.

Conclusion

Il aurait été amusant de pouvoir comparer notre bataille navale avec celle réalisée dans une autre groupe (au niveau des jeux de l’ordinateur). N’ayant pas eu les mêmes consignes, ni les mêmes conventions cela n’a pas été possible. Chez eux par exemple, les bateaux peuvent se toucher, ce qui élimine toute efficacité aux méthodes que nous avons choisies.

Le programme est prêt pour être adapté sous d’autres formes comme le jeu en réseau en modifiant "JoueurAuto" ou l’affichage graphique en remplaçant "Affichage" et quelques broutilles (des ’printf’). Le placement en diagonale des bateaux est aussi possible, au prix d’une réécriture de boucles supplémentaires.

Il est possible d’ajouter un niveau supplémentaire à l’ordinateur, car dans "Niveau2" l’optimisation existe mais pourrait être plus efficace si l’ordinateur tirait en quinconce. La méthode utilisée l’amène souvent à tirer en ligne lorsqu’il y a de grands espaces vides. L’algorithme peut être un peu adapté : au lieu de jouer là où il y le plus d’espace vide en laissant un espace juste suffisant pour éliminer les possibilités de bateaux, on pourrait le faire jouer là où il existe le plus de place (emplacement déterminé par le nombre case vides à la fois en abscisses et en ordonnées, ou par calcul de la densité de tirs déjà réalisés).

Article du 4 août 2007 (673 visite(s)) - Première mise en ligne : 17 mai 2005

Texte, photographies, séquences vidéos et code informatique de P. DELROT, sans autre but que le partage de connaissances. Merci de demander mon accord pour des utilisations commerciales ou à large diffusion. L’utilisation des codes informatiques proposés ne saurait engager ma responsabilité.

Certaines images ou séquences vidéos proposées sont la propriété de leurs auteurs respectifs (que j’indique quand je les connais). Elles seront supprimées sur simple demande (légitime), mon but n’étant pas de porter préjudice à leurs auteurs (copie...).



Electronique, Informatique, Professionnel



Bonne idée !Pyramide de chaussure !

Soutenez les victimes de mines antipersonnel et de BASM


Pyramide de chaussure !

44678 visites, 124 visite(s)/jour
Mis à jour le 23/02/2017 à 22:08
Version : avril 2014

© 1999-2017 Pascal DELROT

Contact / Mentions légales
Creative Commons License
Création(s) mises à disposition sous un contrat Creative Commons.

Site optimisé pour être visible

Site publié grâce à :
Site publié grâce à SPIP 3.1.6 [23598] Réalisé avec openSUSE Linux