Tic Tac Toe – Initiation au développement en JavaScript grâce à VueJS

Le dernier tutoriel vous expliquait comment rendre fonctionnel le jeu du Tic Tac Toe en utilisant le langage de programmation PHP. Cependant, pour les interactions nécessaires au jeu, vous avez dû vous rendre compte que cette méthode n’était pas idéale.

Nous allons voir aujourd’hui comment utiliser le JavaScript afin de rendre fonctionnel le jeu, sans avoir besoin de recharger la page. Pour cela nous allons utiliser le framework progressif VueJS.

Le framework VueJS

Initiation au développement JS avec VueJS

Qu’est-ce qu’un framework ?

“Cadre de travail” en Français, un framework de développement est constitué d’un ensemble de composants qui permet de développer de façon robuste, légère et facile. Bien évidemment, tout est relatif, surtout lorsqu’on parle de facilité, c’est pour cela qu’il faut prendre un grand soin pour choisir son framework, surtout lorsqu’on est débutant.

Le framework VueJS s’adapte pour cela assez bien puisqu’il dispose d’une syntaxe claire et facile à utiliser, et beaucoup d’options disponibles afin de programmer des conditions et des comportements directement en utilisant le HTML, au travers d’une syntaxe spécifique.

Comme pour PHP, je ne saurais que trop vous conseiller de lire la documentation qui explique la façon de procéder.

Pour suivre ce tutoriel, avoir des notions en JavaScript n’est pas nécessaire, puisque je vous expliquerai en détail tout ce que nous allons voir.

À quoi va servir VueJS ?

Dans ce projet, nous allons utiliser VueJS afin de gérer l’affichage en dynamique (sans rechargement de la page) de toute l’application Tic Tac Toe. Plus précisément nous allons :

  • Afficher à qui vient le tour de jouer
  • Afficher la croix ou le rond au clique sur une case vide
  • Tester s’il y a une victoire
  • Afficher le score des deux joueurs indépendamment
  • Afficher le nombre de matchs nuls
  • Implémenter une intelligence artificielle basique pour pouvoir jouer tout seul

Initialisation du Framework et structure du programme

Nous allons d’abord créer la structure de votre application :

votre-application/
├── index.html
├── js/app.js
├── js/vue.js
├── img/cross.png
├── img/cross.png
├── img/circle.png
└── css/style.css

Si vous avez suivi les tutoriels précédents, vous pouvez reprendre votre code, en l’épurant de tout le contenu PHP.

Pour pouvoir utiliser VueJS, il faut le lier à la page que nous utilisons et l’initialiser. La liaison se fait à l’aide d’une simple balise html : script. Cette balise doit s’ajouter entre les <head></head> afin de s’assurer du chargement prioritaire du Framework car c’est sur lui que toute l’application reposera.

<script type="text/javascript" src="js/vue.js"></script>

Il faudra également charger un autre fichier JS, qui contiendra toutes les fonctions du programme. Pour cet exercice, j’ai appelé ce fichier app.js.

<script type="text/javascript" src="js/app.js"></script>

Concernant le fichier index.html, nous allons reprendre ce que nous avons fait dans un tutoriel précédent

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Tic Tac Toe</title>
    <link rel="stylesheet" type="text/css" href="css/style.css">
    <script type="text/javascript" src="js/vue.min.js"></script>
  </head>
<body>
  <header>
    <h1>Tic Tac Toe</h1>
    <p>Ceci est un jeu réalisé par storycom dans un but d’<span>exercice</span> pour un <span>tutoriel de développement JS</span>.</p>
  </header>
  <hr>
  <section class="container page">
 
  <p id="player">Le joueur XX doit jouer</p>
    <div class="tg-wrap">
    <table class="tg">
  <tbody><tr>
    <th class="tg-031e"> </th>
    <th class="tg-031e"> </th>
    <th class="tg-031e"> </th>
  </tr>
  <tr>
    <td class="tg-031e"> </td>
    <td class="tg-031e"></td>
    <td class="tg-031e"> </td>
  </tr>
  <tr>
    <td class="tg-031e"> </td>
    <td class="tg-031e"> </td>
    <td class="tg-031e"></td>
  </tr>
</tbody></table>
</div>
<div class="score">
  <h1>Score</h1>
  <p>Joueur 1 (croix) : XX</p> 
  <p>Joueur 2 (rond) : XX</p>
  <p>Match nul : XX</p>
</div>
<div class="reset"><a>Réinitialiser la partie</a></div>
  </section>
  <hr>
  <footer>
    <p>© StoryCom - 2017 - Tutoriel Tic Tac Toe | Réalisation d'application : <a href="https://www.storycom.fr/">StoryCom</a></p>
  </footer>

<!-- Scripts JS -->
 <script type="text/javascript" src="js/app.js"></script>    

<!-- /Scripts JS -->
</body>
</html>

Le cœur de l’application

C’est dans le fichier app.js que l’application va être conçue. Avant tout nous devons définir une Vue qui contiendra toutes les variables de l’application (scores, match nul, etc.). Il faut garder à l’esprit qu’il n’existe pas qu’une seule solution possible à cette application. Dans celle-ci, nous avons délibérément choisi de nous passer de l’utilisation de tableau (array) pour représenter les 9 cases. La solution est donc un peu plus laborieuse à écrire, mais fonctionne toutefois.

Nous avons besoin de savoir quel joueur doit jouer, le score de chacun des joueurs, le nombre de matchs nuls et les valeurs des neuf cases du Tic Tac Toe. Pour créer et utiliser une Vue, nous devons nous “ancrer” sur un élément qui se trouve sur la page html afin de pouvoir faire la communication entre cette dernière et les fichiers JS. Pour cet exercice, j’ai décidé de m’ancrer sur la classe “page”.

var app = new Vue({
  el: '.page',
  data: {
    player: 1,
    scorej1: 0,
    scorej2: 0,
    matchNul: 0,
    case1: 0,
    case2: 0,
    case3: 0,
    case4: 0,
    case5: 0,
    case6: 0,
    case7: 0,
    case8: 0,
    case9: 0
  }
});

Afin de tester si cela fonctionne, nous allons déjà afficher le tour du joueur qui doit jouer. Pour cela, nous pouvons récupérer les valeurs des variables et les afficher directement grâce au HTML. La récupération des variables se fait simplement à l’aide de : {{ nomDeLaVariable }}. En plus du tour du joueur, nous allons récupérer les scores de chaque joueur ainsi que le nombre de matchs nuls.

...
<p id="player">Le joueur {{player}} doit jouer</p>
...

<div class="score">
  <h1>Score</h1>
  <p>Joueur 1 (croix) : {{scorej1}}</p> 
  <p>Joueur 2 (rond) : {{scorej2}}</p>
  <p>Match nul : {{matchNul}}</p>
</div>

Cela suffit à récupérer les informations voulues. Vous pouvez tester directement le bon fonctionnement dans votre navigateur. Si cela ne fonctionne pas, revoyez les étapes une à une.

Les fonctions de l’application

Chaque application digne de ce nom possède des fonctions. Une fonction est une séquence d’instructions qui exécute une tâche précise. Les fonctions sont le fondement même de la création d’application. Cela permet de “découper” son programme en parties ou en sous parties. Cette fragmentation du code permet de rendre plus claire la lecture de celui-ci, ainsi que son éventuel modification, amélioration ou debuggage.

Dans le cas de notre Tic Tac Toe, nous allons avoir besoin de 3 ou 4 fonctions, selon si nous créons ou non une intelligence artificielle. Il nous faudra  :

  • Une fonction qui permet d’ajouter les croix ou les ronds
  • Une fonction qui teste si un joueur a gagné
  • Une fonction qui change le tour de l’utilisateur
  • Optionnel : Une fonction Intelligence Artificielle qui permettra de jouer seul

La définition d’une fonction se fait en utilisant le mot clé function suivi du nom de la fonction, sans utilisation d’accents ou d’espaces. Une fonction peut prendre ou non des paramètres, cela se définit entre (). Voici un exemple d’une fonction qui ne prend pas de paramètre et d’une fonction qui prend un paramètre.

function maFonctionSansParametre(){
	// Instructions de la fonction sans paramètre
}

function maFonctionAvecUnParametre(parametre){
	// Instructions de la fonction avec paramètre
}

Une fonction peut prendre autant de paramètres que souhaité, pour cela il suffit de les séparer par une virgule. La récupération du paramètre se fera comme si c’était une simple variable déclarée.

Nous allons commencer par créer la fonction qui permet d’ajouter des croix ou des ronds sur les cases. J’ai nommé cette fonction “ajouter”. Celle-ci aura besoin de prendre un paramètre : le numéro de la case. Nous allons avoir besoin de :

  • Récupérer la valeur envoyée (numéro de la case)
  • Tester si la case récupérée est vide
  • Si la case récupérée est vide, ajouter le rond ou la croix en fonction du joueur
  • Tester s’il y a eu victoire (fonction)
  • Changer de joueur (fonction)
function ajouter(numCase){
	// On converti numCase en nombre entier
	numCase = parseInt(numCase);

	// Test si la case est égale à 1 et caseX = 0
	if(numCase == 1 && app.case1 == 0){
		// attribue la valeur de player à la case
		app.case1 = app.player;
		// lance fonction testVictoire et ChangePlayer
		testVictoire();
		changePlayer();
	} else if(numCase == 2 && app.case2 == 0){
		app.case2 = app.player;
		testVictoire();
		changePlayer();
	}
	// faire tous les tests, jusqu'à la 9e case.
}

Vous remarquerez que pour accéder aux variables de la Vue en passant par le fichier JS, nous devons utiliser le nom de cette Vue (ici app), alors que sur le HTML nous devons utiliser uniquement le nom de la variable.

Vous devez faire attention dans vos conditions à utiliser le double égal (==) pour tester s’il y a une égalité. Si vous n’en utilisez qu’un (=), cela revient à attribuer une valeur à la variable.

Dans notre application nous définissons le player grâce à la valeur 1 ou 2, pour joueur 1 ou joueur 2. Nous utilisons également ces valeurs pour indiquer si les cases sont vides (0), prises par le premier joueur (1), prises par le second joueur (2).

La fonction testVictoire doit tester toutes les combinaisons possibles pour voir si un joueur à gagné. Pour le Tic Tac Toe, ce n’est pas nécessaire de trouver un algorithme qui permet de parcourir automatiquement les cases afin de tester la victoire. Comme il n’y a que 9 cases, soit 8 possibilités de victoires par chaque joueur, nous pouvons aisément tester toutes les possibilités. Nous devons le faire pour le joueur un (app.player == 1), ainsi que pour le joueur deux. Pour cela nous avons besoin :

  • Vérifier si c’est le joueur un qui joue
  • Sinon c’est le joueur deux
  • Tester s’il y a une victoire (case1 == 1 &&  case2 == 1 et case3 == 1)…
  • S’il y a une correspondance, incrémenter (app.scorej1++ ou app.scorej2++) de 1 le score du joueur vainqueur
  • Réinitialiser toutes les cases
  • Tester si on n’entre dans aucune des conditions ci-dessus, mais que toutes les cases sont remplies (app.case1 > 0 && app.case2 > 0, etc.)
  • Si c’est le cas, réinitialiser toutes les cases
  • Incrémenter le compteur de match nul (app.matchNul++)
function testVictoire(){
	if(app.player == 1){
		if(app.case1 == 1 && app.case2 == 1 && app.case3 == 1){
			app.scorej1++;
			app.case1 = app.case2 = app.case3 = app.case4 = app.case5 = app.case6 = app.case7 = app.case8 = app.case9 = 0;
		} else if(app.case1 == 1 && app.case4 == 1 && app.case7 == 1){
			app.scorej1++; 
			app.case1 = app.case2 = app.case3 = app.case4 = app.case5 = app.case6 = app.case7 = app.case8 = app.case9 = 0;
		}
		// Ecrire tous les cas pour le J1
	} else {
		if(app.case1 == 2 && app.case2 == 2 && app.case3 == 2){
			app.scorej2++; 
			app.case1 = app.case2 = app.case3 = app.case4 = app.case5 = app.case6 = app.case7 = app.case8 = app.case9 = 0;
		}
		else if(app.case1 == 2 && app.case4 == 2 && app.case7 == 2){
			app.scorej2++; 
			app.case1 = app.case2 = app.case3 = app.case4 = app.case5 = app.case6 = app.case7 = app.case8 = app.case9 = 0;
		}
		// Ecrire tous les cas pour le J2
	}
}

Pour finir avec les fonctions non optionnelles, nous devons en créer une qui permet de changer de joueur. Pour cela nous devons simplement changer la valeur de app.player en lui attribuant soit 1 soit 2.

function changePlayer(){
	if (app.player == 1)
		app.player = 2;
	else
		app.player = 1;
}

Vous remarquerez que je n’ai pas ouvert et fermé les accolades {} de la condition if, else. C’est parce que lorsqu’une condition ne possède qu’une seule instruction, l’ouverture et fermeture des accolades devient optionnelle. Dans notre cas cela nous permet de gagner en lisibilité.

Toutes nos fonctions sont rédigées, nous avons tout ce qu’il faut pour finir le jeu pour deux joueurs sans IA.

Rendre fonctionnel l’application

Le framework VueJS offre un panel de fonctionnalités à utiliser, parmi celles-ci, nous pouvons utiliser des conditions (if, else, else if), des boucles, afficher/masquer des éléments etc. Nous allons avoir besoin de :

  • Récupérer le clique sur une case et lancer la fonction ajouter
  • Afficher le rond ou la croix en fonction du joueur
  • Afficher le nombre de matchs nuls si ils sont supérieur à 0

Pour récupérer un clique sur un élément, il faut utiliser l’attribut v-on:click, auquel on peut lui faire passer une variable, le numéro de la case cliquée. Pour afficher un élément, il faut utiliser l’attribut v-if, et tester nos variables.

<!-- Lancer la fonction ajouter sur la case 1 / afficher l'image de la croix si la case 1 = 1, afficher l'image du rond si la case 1 = 2 -->
<th class="tg-031e"><a v-on:click="ajouter(1)"><img v-if="case1 == 1" src="../img/cross.png"> <img v-if="case1 == 2" src="../img/circle.png">  </a></th>

<!-- Lancer la fonction ajouter sur la case 2 / afficher l'image de la croix si la case 2 = 1, afficher l'image du rond si la case 2 = 2 -->
 <th class="tg-031e"><a v-on:click="ajouter(2)"> <img v-if="case2 == 1" src="../img/cross.png"> <img v-if="case2 == 2" src="../img/circle.png"> </a></th>

<!-- Faire ceci pour toutes les cases -->

<!-- Afficher le nombre de match nul si > 0 -->
<p v-if="matchNul > 0">Match nul : {{matchNul}}</p>

A ce stade du développement de l’application est fonctionnelle. Elle compte le score de chaque joueur, elle affiche le nombre de matchs nuls s’il est supérieur à 0 et on peut jouer à deux joueurs. S’il y a une victoire, ou s’il y a un match nul.

Pour améliorer l’application, vous pouvez également créer une intelligence artificielle qui générera aléatoirement un nombre entre 1 et 9 grâce à la fonction suivante :

var nb = parseInt (Math.random() * (9 - 1) + 1);

Puis attribuer la valeur de l’IA à cette case (2) si cette case est vide, sinon relancer la fonction intelligence artificielle qui générera a nouveau aléatoirement un nombre jusqu’à ce qu’il trouve une case de libre.

N’hésitez pas à laisser un message en commentaire si vous rencontrez un problème pour réaliser ce tutoriel.