Code source du projet de la bataille navale

Voir le résultat   Retour à la page du projet

Afficher/Masquer les commentaires

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8"/>
<title>Jeu de bataille navale</title>
<meta name="description" content="Un jeu de bataille navale programmé en JavaScript."/>
<style>

Tous les éléments td de la table du jeu sont de classe caseBataille. Cela permet d'uniformiser les dimensions de toutes les cases.

Le réglage text-align:center est utilisé pour que les nombres et lettres affichées sur la première ligne et la première colonne du tableau soient centrés dans les cases.

	.caseBataille{
		width:20px;
		height:20px;
		text-align:center;
	}
</style>
</head>
 
<body>

Voici l'élément table du jeu. L'attribut border="1" indique que les bordures des éléments du tableau doivent être affichées.

<table id="plateau" border="1">

L'élément table contient des éléments tr qui représentent les lignes. Chaque élément tr contient des éléments td qui représentent les différentes cases de la ligne. Comme nous l'avons déjà dit tous les éléments td sont de classe caseBataille ce qui entraîne que la règle CSS vue plus haut s'applique.

<tr>
<td></td>
<td class="caseBataille">A</td>
<td class="caseBataille">B</td> 
<td class="caseBataille">C</td>
<td class="caseBataille">D</td>
<td class="caseBataille">E</td>
<td class="caseBataille">F</td>
<td class="caseBataille">G</td>
<td class="caseBataille">H</td>
<td class="caseBataille">I</td>
<td class="caseBataille">J</td>
</tr>
<tr>
<td class="caseBataille">1</td>

Les éléments td des cases du jeu sont identifiés par leur position selon le système de repérage utilisé à la bataille navale : lettre de la colonne suivie du numéro de la ligne.

<td class="caseBataille" id="A1"></td>
<td class="caseBataille" id="B1"></td>
<td class="caseBataille" id="C1"></td>
<td class="caseBataille" id="D1"></td>
<td class="caseBataille" id="E1"></td>
<td class="caseBataille" id="F1"></td>
<td class="caseBataille" id="G1"></td>
<td class="caseBataille" id="H1"></td>
<td class="caseBataille" id="I1"></td>
<td class="caseBataille" id="J1"></td>
</tr>
<tr>
<td class="caseBataille">2</td>
<td class="caseBataille" id="A2"></td>
<td class="caseBataille" id="B2"></td>
<td class="caseBataille" id="C2"></td>
<td class="caseBataille" id="D2"></td>
<td class="caseBataille" id="E2"></td>
<td class="caseBataille" id="F2"></td>
<td class="caseBataille" id="G2"></td>
<td class="caseBataille" id="H2"></td>
<td class="caseBataille" id="I2"></td>
<td class="caseBataille" id="J2"></td>
</tr>
<tr>
<td class="caseBataille">3</td>
<td class="caseBataille" id="A3"></td>
<td class="caseBataille" id="B3"></td>
<td class="caseBataille" id="C3"></td>
<td class="caseBataille" id="D3"></td>
<td class="caseBataille" id="E3"></td>
<td class="caseBataille" id="F3"></td>
<td class="caseBataille" id="G3"></td>
<td class="caseBataille" id="H3"></td>
<td class="caseBataille" id="I3"></td>
<td class="caseBataille" id="J3"></td>
</tr>
<tr>
<td class="caseBataille">4</td>
<td class="caseBataille" id="A4"></td>
<td class="caseBataille" id="B4"></td>
<td class="caseBataille" id="C4"></td>
<td class="caseBataille" id="D4"></td>
<td class="caseBataille" id="E4"></td>
<td class="caseBataille" id="F4"></td>
<td class="caseBataille" id="G4"></td>
<td class="caseBataille" id="H4"></td>
<td class="caseBataille" id="I4"></td>
<td class="caseBataille" id="J4"></td>
</tr>
<tr>
<td class="caseBataille">5</td>
<td class="caseBataille" id="A5"></td>
<td class="caseBataille" id="B5"></td>
<td class="caseBataille" id="C5"></td>
<td class="caseBataille" id="D5"></td>
<td class="caseBataille" id="E5"></td>
<td class="caseBataille" id="F5"></td>
<td class="caseBataille" id="G5"></td>
<td class="caseBataille" id="H5"></td>
<td class="caseBataille" id="I5"></td>
<td class="caseBataille" id="J5"></td>
</tr>
<tr>
<td class="caseBataille">6</td>
<td class="caseBataille" id="A6"></td>
<td class="caseBataille" id="B6"></td>
<td class="caseBataille" id="C6"></td>
<td class="caseBataille" id="D6"></td>
<td class="caseBataille" id="E6"></td>
<td class="caseBataille" id="F6"></td>
<td class="caseBataille" id="G6"></td>
<td class="caseBataille" id="H6"></td>
<td class="caseBataille" id="I6"></td>
<td class="caseBataille" id="J6"></td>
</tr>
<tr>
<td class="caseBataille">7</td>
<td class="caseBataille" id="A7"></td>
<td class="caseBataille" id="B7"></td>
<td class="caseBataille" id="C7"></td>
<td class="caseBataille" id="D7"></td>
<td class="caseBataille" id="E7"></td>
<td class="caseBataille" id="F7"></td>
<td class="caseBataille" id="G7"></td>
<td class="caseBataille" id="H7"></td>
<td class="caseBataille" id="I7"></td>
<td class="caseBataille" id="J7"></td>
</tr>
<tr>
<td class="caseBataille">8</td>
<td class="caseBataille" id="A8"></td>
<td class="caseBataille" id="B8"></td>
<td class="caseBataille" id="C8"></td>
<td class="caseBataille" id="D8"></td>
<td class="caseBataille" id="E8"></td>
<td class="caseBataille" id="F8"></td>
<td class="caseBataille" id="G8"></td>
<td class="caseBataille" id="H8"></td>
<td class="caseBataille" id="I8"></td>
<td class="caseBataille" id="J8"></td>
</tr>
<tr>
<td class="caseBataille">9</td>
<td class="caseBataille" id="A9"></td>
<td class="caseBataille" id="B9"></td>
<td class="caseBataille" id="C9"></td>
<td class="caseBataille" id="D9"></td>
<td class="caseBataille" id="E9"></td>
<td class="caseBataille" id="F9"></td>
<td class="caseBataille" id="G9"></td>
<td class="caseBataille" id="H9"></td>
<td class="caseBataille" id="I9"></td>
<td class="caseBataille" id="J9"></td>
</tr>
<tr>
<td class="caseBataille">10</td>
<td class="caseBataille" id="A10"></td>
<td class="caseBataille" id="B10"></td>
<td class="caseBataille" id="C10"></td>
<td class="caseBataille" id="D10"></td>
<td class="caseBataille" id="E10"></td>
<td class="caseBataille" id="F10"></td>
<td class="caseBataille" id="G10"></td>
<td class="caseBataille" id="H10"></td>
<td class="caseBataille" id="I10"></td>
<td class="caseBataille" id="J10"></td>
</tr>
</table>
<br/>

Ici nous avons la zone de saisie et le bouton.

<input type="text" id="coup" /><input type="button" id="jouer" value="Valider"/>

Le code JavaScript du programme figure dans le fichier séparé : bataille.js

<script src="bataille.js"></script>
</body>
</html>

Afficher/Masquer les commentaires

C'est le tableau plateau qui contient l'état des cases du jeu. Le codage est le suivant :

  • 0 : case eau,

  • 1 : case de porte-avions,

  • 2 : case de croiseur,

  • 3 : case de contre-torpilleur,

  • 4 : case de sous-marin,

  • 5 : case torpilleur.

En outre une case déjà jouée est codée par un nombre négatif : -1 pour le porte-avions, -2 pour le croiseur, etc.

Une case eau jouée est codée -6.

Le contenu initial est généré de façon aléatoire en appelant la fonction placeBateaux.

var plateau=[];
placeBateaux();

Le tableau navires contient le nombre de cases restantes à découvrir pour chacun des bateaux.

  • navires[0] : ne sert à rien,

  • navires[1] : 5 cases pour le porte-avion,

  • navires[2] : 4 cases pour le croiseur,

  • navires[3] : 3 cases pour le contre-torpilleur,

  • navires[4] : 3 cases pour le sous-marin,

  • navires[5] : 2 cases pour le torpilleur.

var navires=[0,5,4,3,3,2];

Nombre total de cases de navires trouvées par le joueur, pour gagner il doit découvrir les 17 cases de bateaux.

var touches=0;

La variable finPartie est mise à la valeur true lorsque la partie est terminée.

La variable nbCoups, comme son nom l'indique, compte le nombre de coups joués.

var finPartie=false;
var nbCoups=0;

Le tableau message contient tous les messages possibles selon les différentes situations.

var message=[];
message[0]="A l'eau !";
message[1]="Porte-avion touché !";
message[2]="Croiseur touché !";
message[3]="Contre-torpilleur touché !";
message[4]="Sous-marin touché !";
message[5]="Torpilleur touché !";
message[6]="Case déjà jouée !";
message[11]="Porte-avion coulé !";
message[12]="Croiseur coulé !";
message[13]="Contre-torpilleur coulé !";
message[14]="Sous-marin coulé !";
message[15]="Torpilleur coulé !";

Les lignes qui suivent mettent en place le dispositif d'interaction du joueur avec le programme.

  • le coup proposé par le joueur (saisi dans la zone de texte) est joué en appelant jouerCoup, cela peut être déclenché soit en appuyant sur le bouton, soit en appuyant sur la touche "entrée".

  • la fonction attenteCoup remet l'interface utilisateur prête à recevoir une nouvelle proposition du joueur : la zone de saisie est vidée et elle reçoit le curseur.

var coup=document.getElementById("coup");
var jouer=document.getElementById("jouer");

jouer.onclick=function(){	
	jouerCoup(coup.value);
	attenteCoup();
}

coup.onkeypress=function(event){
	if(event.keyCode==13){
		jouer.onclick(); //entrée c'est l'équivalent d'un clic sur le bouton
	}
}

function attenteCoup(){
	coup.value="";
	coup.focus();
}

conversion(position)

Fonction pour convertir une position au format "bataille navale" en position au format numéros de ligne/colonne du tableau plateau.

  • Paramètre : une chaine de caractères qui doit contenir une position au format "bataille navale" comme par exemple A1, C5, etc.

  • Retour : un objet contenant deux propriétés colonne et ligne qui indiquent la position correspondante dans le tableau plateau.

function conversion(position){ 

La lettre de colonne est précisée par le premier caractère de position, l'instruction charCodeAt(0) retourne le code ASCII de cette lettre (en position 0 dans la chaîne). Le code de A est 65, de B est 66 etc., du coup en retranchant 65 on obtient le numéro de colonne de 0 à 9.

	var colonne=position.charCodeAt(0)-65;

Le numéro de ligne figure dans position à partir du caractère numéroté 1, l'instruction slice(1) donne cette partie de la chaîne de caractères ; avec le parseInt nous la convertissons en nombre entier. A la bataille navale le premier numéro de ligne est 1, par contre dans le tableau la numérotation commence à 0, donc nous retranchons 1 pour terminer la conversion.

	var ligne=parseInt(position.slice(1))-1;

Nous retournons un objet avec les deux propriétés colonne et ligne.

	return {colonne:colonne, ligne:ligne};	
}

getCodeCase(position)

Fonction pour connaître le code de l'état d'une case du jeu.

  • Paramètre :

    • position : position d'une case au format "bataille navale".

  • Retour : code de l'état de la case obtenu depuis le tableau plateau.

function getCodeCase(position){
	var c=conversion(position);
	return plateau[c.ligne][c.colonne];
}

setCodeCase(position,valeur)

Fonction pour définir le code de l'état d'une case du jeu.

  • Paramètres :

    • position : position d'une case au format "bataille navale".

    • valeur : code de l'état à attribuer à cette case (dans le tableau plateau).

function setCodeCase(position,valeur){
	var c=conversion(position);
	plateau[c.ligne][c.colonne]=valeur;
}

majVueJeu(position,situation)

Fonction pour mettre à jour l'affichage du jeu et informer le joueur.

  • Paramètres :

    • position : position de la case qui doit être mise à jour à l'affichage (au format "bataille navale").

    • situation : numéro de la situation de jeu (les différentes situations sont numérotées entre 0 et 15).

function majVueJeu(position,situation){

Lorsque la partie est terminée finPartie vaut true et le joueur est informé par un ajout au message. Le joueur peut alors rejouer grâce à l'instruction location.reload() qui recharge tout simplement la page.

Dans le cas contraire seul le message de situation est affiché.

	if(finPartie){
		alert(message[situation]+"\nVous avez coulé tous les navires en "+nbCoups+" coups");
		location.reload();
	}else{	
		alert(message[situation]);
	}

Par défaut la nouvelle couleur de la case est rouge, sauf si le code de la case vaut -6 ("à l'eau") où elle est bleue claire.

	var couleur="#FF0000";
	if (getCodeCase(position)==-6){couleur="#BBBBFF";}
	document.getElementById(position).style.backgroundColor=couleur;	
}

jouerCoup(position)

Fonction qui contient la logique du jeu. Cette fonction est exécutée chaque fois que le joueur fait une proposition.

  • Paramètre :

    • position : position de la case proposée par le joueur au format "bataille navale".

function jouerCoup(position){
	nbCoups++;
	var codeCase=getCodeCase(position);

Par défaut le numéro de situation prend la valeur du code de l'état de la case.

	var situation=codeCase;
  • si la case est à l'état 0 : c'est de l'eau, elle devient une case "à l'eau" (codée -6),

  • si la case est celle d'un navire (états 1 à 5), c'est touché :

    • le navire perd un élément,

    • si le nombre d'éléments du navire tombe à 0, le numéro de situation est augmenté de 10 : en effet les messages qui indiquent qu'un navire est coulé sont numérotés de 11 à 15,

    • le code de l'état de la case est opposé,

    • le nombre total de cases "touché" est incrémenté,

    • si les 17 éléments de bateau ont été trouvés la variable finPartie prend la valeur true.

  • autrement, le joueur a proposé une case déjà jouée, ce qui correspond à la situation numérotée 6.

	switch(codeCase){
		case 0:
			setCodeCase(position,-6);
		break;
		case 1: case 2: case 3: case 4: case 5:
			navires[codeCase]--;
			if(navires[codeCase]==0){situation+=10;}
			setCodeCase(position,-codeCase);

			touches++;
			if(touches==17){finPartie=true;}			
		break;
		default:
			situation=6;
	}

Une fois les données du jeu mises à jour et le numéro de situation déterminé, nous appelons la fonction majVueJeu pour communiquer au joueur le résultat de son action via l'interface utilisateur.

	majVueJeu(position,situation);
}

placeBateau(ligneDepart,colonneDepart,vertical,code,longueur)

Fonction qui tente de placer dans le tableau plateau les codes de cases associés à un bateau.

  • Paramètres :

    • ligneDepart,colonneDepart : position de départ du bateau dans le tableau.

    • vertical : si ce paramètre vaut true le bateau est placé verticalement, s'il vaut false il est placé horizontalemment.

    • code : code du bateau (1 pour le porte-avions, 2 pour le croiseur, etc.)

    • longueur : nombre de cases occupées par le bateau (5 pour le porte-avions, 4 pour le croiseur, etc.)

  • Retour : true ou false selon que le placement a réussi ou non.

function placeBateau(ligneDepart,colonneDepart,vertical,code,longueur){
	var incrementLigne,incrementColonne;	
	var succes=true;

Définition des incréments en ligne et en colonne pour calculer les différentes positions des éléments du bateau à partir de la position de départ et selon qu'il est placé verticalement ou horizontalement.

	if(vertical){
		incrementLigne=1;
		incrementColonne=0;
	}else{
		incrementLigne=0;
		incrementColonne=1;
	}

Boucle pour tester si toutes les cases où doit prendre place le bateau son disponibles. Si une case est déjà occupée, nous sortons immédiatement de la boucle avec succes qui vaut false pour indiquer l'échec.

	for(var i=0;i<longueur;i++){
		if(plateau[ligneDepart+i*incrementLigne][colonneDepart+i*incrementColonne]!=0){
			succes=false;
			break;		
		}
	}

En cas de succès le tableau plateau est réellement modifié avec le code du navire aux emplacements qui sont donc libres.

	if(succes){
		for(var i=0;i<longueur;i++){
			plateau[ligneDepart+i*incrementLigne][colonneDepart+i*incrementColonne]=code;
		}
	}

	return succes;
}

positionHasardBateau(code,longueur)

Fonction qui positionne au hasard un navire dans le tableau plateau. Cette fonction est appelée par la fonction placeBateaux pour positionner aléatoirement les 5 navires au début de la partie.

  • Paramètres :

    • code : code des cases du navire à placer : 1 pour le porte-avions, 2 pour un croiseur, etc.

    • longueur : nombre de cases du navire : 5 pour le porte-avions, 4 pour le croiseur, etc.

function positionHasardBateau(code,longueur){
	var departLimite,depart;	
	var succes=false;

La position de départ du bateau est tirée au sort, mais il n'est pas toujours possible de le placer car il ne faut pas qu'une des cases se superpose avec une case d'un autre bateau déjà placé. La fonction placeBateau tente de placer le navire et retourne true ou false selon que le placement a réussi ou non.

La boucle while permet de tirer de nouvelles positions pour le bateau jusqu'à ce qu'il puisse être placé.

	while(!succes){

La variable departLimite tient compte de la longueur du bateau dans le tirage aléatoire, par exemple si le bateau occupe 3 cases, departLimite sera un nombre entier au hasard entre 0 et 7 : horizontalement ou verticalement le bateau ne peut pas être placé à moins de 3 cases du bord.

		departLimite=Math.floor(Math.random()*(11-longueur));
		depart=Math.floor(Math.random()*10);

Equiprobablement, nous tentons de placer le bateau horizontalement ou verticalement.

		if(Math.random()<0.5){
			succes=placeBateau(departLimite,depart,true,code,longueur);
		}else{
			succes=placeBateau(depart,departLimite,false,code,longueur);
		}
	}
}

placeBateaux()

Fonction qui initialise le tableau des cases du jeu (tableau plateau) en positionnant au hasard les 5 navires.

function placeBateaux(){

Tableau rempli de 0.

	for(var ligne=0;ligne<=9;ligne++){
		plateau[ligne]=[0,0,0,0,0,0,0,0,0,0];
	}

Placement au hasard des 5 bateaux.

	positionHasardBateau(5,2);	
	positionHasardBateau(3,3);
	positionHasardBateau(4,3);
	positionHasardBateau(2,4);
	positionHasardBateau(1,5);
}

Fonction appelée au chargement de la page pour donner le curseur à la zone de saisie.

attenteCoup();