Jeu de morpions JavaScript
Les règles simplissimes du morpions en font un exercice
idéal de programmation. C'est en JavaScript que nous nous
proposons de développer l'algorithme de ce jeu. Mais si JavaScript
n'est pas votre tasse de... café, sachez que vous pouvez
quand même, à l'aide d'une seule
balise HTML, afficher ce jeu dans vos pages perso.
Mise en place du jeu en HTML
Le jeu doit s'afficher dans une page HTML. Nous utilisons un tableau
de 12 cellules pour y insérer des champs de formulaire. Un
simple éditeur de texte nous suffira pour le saisir. Le formulaire
est baptisé "toto".
<HTML><HEAD></HEAD><BODY>
<FORM NAME="toto">
<TABLE BORDER=0>
<TR>
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
</TR>
<TR>
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
</TR>
<TR >
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
<TD ALIGN=center>
<INPUT TYPE=text VALUE="X" SIZE=1
MAXLENGTH=1 >
</TD>
</TR>
<TR>
<TD ALIGN=center COLSPAN=3>
<INPUT TYPE=button
VALUE="Effacer" >
</TD>
</TR>
</TABLE>
</FORM></BODY></HTML>
Le code JavaScript
La code HTML étant en place, nous devons maintenant
inclure dans la balise HEAD, les fonctions qui vont animer notre
jeu. Commençons par le contrôle le plus simple :
un bouton effaçant le contenu de chacune des 9 cellules afin
de permettre de rejouer. Nous allons déclarer une fonction
qui aura ce rôle et faire en sorte qu'un clic sur le bouton
lance son exécution.
On insère une balise <SCRIPT> dans l'en-tête
du document :
<HEAD><SCRIPT LANGUAGE="JavaScript">
function efface(){
for (n=0; n<=8; n++) {document.toto.elements[n].value="''
}
}
</SCRIPT></HEAD>
Notre fonction boucle 9 fois en incrémentant une variable
n. Chaque fois un élément du formulaire "toto", élément
désigné par sa position dans le tableau "elements"
est vidé de tout contenu. Rappelons que c'est le navigateur
qui tient comptabilité des formulaires et des éléments
de formulaire présents dans le document, en deux tableaux
nommés "forms" et "elements". L'expression "document.forms[0]elements[0] est du
pur JavaScript et désigne toujours le premier objet (l'index
commence à zéro) du premier formulaire d'un document.
Dès lors notre bouton de formulaire peut jouer son rôle .
Il suffit d'inclure dans la balise qui le définit, un gestionnaire
d'événement "onClick" qui appelle l'exécution
de la fonction créée :
<INPUT TYPE=button VALUE="Effacer" onClick="efface()">
Ça marche ! Occupons nous maintenant de rendre ce jeu convivial.
Un clic doit suffire à l'utilisateur pour placer sa croix
dans une cellule. Les champs de formulaire ignorant l'événement
onClick nous interceptons un autre type d'action : l'activation
du champs par positionnement du curseur d'insertion. Cet événement
est nommé "Focus". Pour le reste, le procédé
d'écriture du script est le même : On déclare
un fonction ("jeuPerso") exécutant l'action souhaitée,
dans la balise script d'en-tête du document. Puis on veille
à appeler cette fonction en modifiant le code HTML. La fonction
d'abord : elle doit connaître la cellule cliquée afin
d'en changer la valeur si elle est vide. Nous lui passerons donc
cette information en paramètre (CaseDuClic) lors de son appel.
function jeuPerso(CaseDuClic){
if ( CaseDuClic.value=="" ) { CaseDuClic.value='X'
}
}
Pour appeler la fonction nous modifions comme suit le code HTML
définissant chaque champs de texte du formulaire.
<INPUT TYPE=text VALUE="X" SIZE=1 MAXLENGTH=1 onFocus="jeuPerso(this)">
"This" désigne l'objet en cours, ici l'élément
de formulaire cliqué. C'est lui qu'il nous faut passer à
la fonction (dans la variable CaseDuClic).
Il ne nous manque plus qu'une chose mais de taille : un fonction
permettant à la machine de jouer à son tour. Une telle
fonction, nous pourrions la nommer "jeuAuto()" et faire en sorte
qu'elle soit appelée immédiatement après jeuPerso().
C'est là un chose aisée :
function jeuPerso(CaseDuClic){
if ( CaseDuClic.value=="" ) { CaseDuClic.value='X'
}
jeuAuto()
}
Plus difficile est de concevoir cette fonction jeuAuto().
Il s'agit ni plus ni moins que d'apprendre à une machine
les règles du morpions ! Une analyse préalable
s'impose.
L'algorithme du jeu
Avant d'écrire la fonction jeuAuto() nous devons nous demander
comment NOUS jouons nous au morpions lorsque c'est notre tour de
jouer.
Nous cherchons tout d'abord un coup gagnant qui mettrait fin
à la partie. Avec la même urgence aussi, nous cherchons
à parer un coup prochain de l'adversaire qui serait un
coup gagnant pour lui. Notez que dans ces deux cas, nous cherchons
sur tous les axes du jeu, deux cases remplies identiquement, accompagnées
d'une troisième case vide. Dans tous les cas, que ces deux
cases soient remplies par nous ou par notre adversaire, nous DEVONS
occuper la troisième !
Ensuite, si notre première recherche n'aboutit pas, nous
cherchons à effectuer un coup pertinent. Parler de tactique
ici semble un peu forcé. Nous ne saurions donner qu'une
seule case dont l'occupation est tactique : le centre du
plateau. Cette position est la seule qui entre dans la constitution
de 4 lignes.
Enfin, si le centre est déjà occupé, il
y-a -t'il autre chose à faire que de se placer sur la première
case vide ? Certes un algorithme plus pertinent jouerais ce coup
en fonction de celui de l'adversaire. Notre jeu deviendrait ainsi
imbattable. Mais paradoxalement il ne nous semble pas inintéressant
que notre jeu ait cette faiblesse. Qui voudrait jouer avec l'assurance
qu'il va perdre ?
Notre fonctions jeuAuto() devra donc procéder de même.
Chercher d'abord à occuper une place nécessaire (coup
gagnant ou coup défensif obligé), chercher en un deuxième
temps s'il est possible d'occuper la case centrale, enfin en désespoir
de cause, occuper la première cellule vide. Notre fonction
peut être décomposée en trois sous fonctions
que nous nommerons : UnCoupObligé(), LaCaseCentrale(),
UneCaseVide(). Nous ferons en sorte que ces fonctions renvoient
une valeur "true" ou "false" afin de pouvoir écrire :
function jeuAuto() {
if ( UnCoupObligé() ) { }
else {
if ( LaCaseCentrale()
) { }
else {
UneCaseVide();
return null
}
}
}
De la sorte, les deuxième fonction ne sera exécutée
que si celle qui précède renvoie une valeur fausse.
De même la dernière fonction de s'exécutera
qu'à la condition que le centre est déjà occupé
(la fonction LaCaseCentrale() renvoyant dans ce cas la valeur fausse).
Nous commençons par rédiger la fonction UneCaseVide().
Cette fonction appelée en dernier recours doit identifier
la première case vide et y placer un "O" correspondant au
coup joué par la machine. Toujours dans la balise <SCRIPT...>
on insère maintenant les lignes suivantes :
function UneCaseVide() {
for (n=0; n<=8; n++) {
// pour chacune des 9 cases, on teste si elle est vide
if (document.toto.elements[n].value=="") {
document.toto.elements[n].value="O";
//
auquel cas on s'y place
return null
//
et on sort de la boucle
}
}
}
La fonction qui vérifie si la case centrale est disponible
et renvoie "false dans le cas contraire ne pose pas d'avantage de
problème :
function LaCaseCentrale() {
if ( document.toto.elements[4].value=="" ) { /* Le
cinquième objet du formulaire, indexé 4, est la cellule
centrale */
document.toto.elements[4].value="O";
return true
}
else { return false} //
en retournant "false, on donne lieu
} //
à l'exécution de la fonction UneCaseVide()
"Last but not least" la fonction UnCoupObligé() va nous
contraindre à saisir beaucoup plus de code. Cette fonction
doit très précisément prendre chacun des axes
du jeu pour vérifier si s'y trouve deux valeurs identique
(croix ou cercle) et une case vide. Dans cette configuration en
effet, il FAUT jouer dans la case vide. La fonction renverra "false"
si un tel état de fait n'est pas trouvé afin de laisser
s'exécuter les fonctions suivantes LaCaseCentrale()
ou UneCaseVide().
Il faut tester chaque axe du jeu c'est-à-dire qu'il faut
observer plusieurs séries de cellules. Notre premier travail
va consister à établir la liste de ces axes ou séries
de cases. Nous nommerons ces 8 lignes ou séries possibles
axeN.
function UnCoupObligé() {
/*
Création de 9 tableaux (axe1, axe2, axe3,...) de 4 entrées
chacun (la première entrée étant indexée
0, nous ne l'utiliserons pas par commodité. */
for (n=1; n<=8; n++) { eval ("axe" + n +" = new Array(4)") }
// population des tableaux
axe1, axe2, axe3, séries horizontales
for (n=1; n<=3; n++) {
axe1[n] = document.toto.elements[n-1]
/*
rappel: l'élément Array est indexé depuis 0
*/
}
for (n=4; n<=6; n++) {
axe2[n-3] = document.toto.elements[n-1]
}
for (n=7; n<=9; n++) {
axe3[n-6] = document.toto.elements[n-1]
}
// population des tableaux
axe4, axe5, axe6, séries verticales
for (n=1; n<=3; n++) {
for (x=1 ; x<=3 ; x++) {
eval ( "axe" + (x+3) + "[n] = axe" +
n + "[x]")
/* par exemple : axe"3+3" [2] = axe2 [3] * /
}
}
// première diagonale 7ème
axe
for (n=1; n<=3 ; n++) {
eval ( "axe7[n]=axe" +n+ "[n]" )
}
// population du huitième axe (du haut
droit vers le bas gauche)
axe8[1] = axe1[3];
axe8[2] = axe2[2];
axe8[3] = axe3[1];
On dispose dès lors de 8 tableaux ou listes reprenant les
axes ou lignes du jeu. Il nous est possible de tester une à
une ces lignes afin de déterminer si l'une d'entre elles
contient 2 valeurs identiques non vides et une troisième
vide. Nous pourront ainsi agir en conséquence. L'algorithme
est simple et pourtant efficace. Il pourra resservir à d'autre
langage de programmation... ;-)
// algorithme de test
for (n=1; n<=8; n++) {
y = eval ("axe" + n) /*
à chaque entrée dans la boucle "y" représente
une ligne à tester */
if ( y[1].value == y[2].value &&
y[1].value != "" && y[3].value == "" ){
y[3].value = "O";
return true
}
if ( y[1].value == y[3].value &&
y[1].value != "" && y[2].value == "" ){
y[2].value="O";
return true
}
if ( y[3].value == y[2].value &&
y[2].value != "" && y[1].value == "" ){
y[1].value="O";
return true
}
} /*
enfin si ce test des axes ne donne aucun resultat, la fonction retourne
false */
return false
}
Notre jeu est prêt. Les fanatiques du morpions auront tôt
fait de déceler les faiblesses de l'algorithme et de trouver
les séquences gagnantes. B2,C1,C3 ou C1, A3, C3. Nous pourrions
aménager aisément la fonction UneCaseVide() afin d'éviter
à l'ordinateur une défaite mais il nous semble que
notre jeu est plus intéressant ainsi.
Utiliser le jeu sur votre site
Yazo.net vous offre d'afficher un jeu de morpions sur votre page
perso sans écrire une ligne de JavaScript. Insérer
seulement dans votre code HTML, à l'emplacement souhaité,
la ligne suivante :
<SCRIPT LANGUAGE="JavaScript"
SRC="http://www.yazo.net/techniquest/morpions.js"></SCRIPT>
Prévoir 60 x 160 pixels minimun. Connexion rapide préferable
! Un exemple dans un cadre bleu :
<table bgcolor="blue">
<tr><td>
<script language="JavaScript" src="http://www.yazo.net/techniquest/morpions.js></script>
</td></tr></table>
Affichera sur votre homepage :
Dans un article ancien, le CrapoWeb présentait les notions
nécessaires pour débuter en JavaScript.
Netscape propose le téléchargement du manuel de référence
de JavaScript sur son site : http://developper.netscape.com/docs/manuals/
communicator/jsguide4/index.htm
<
Sommaire
|