/*
Auteur: Eric Leydet
Adresse électronique: Eric.Leydet@ac-bordeaux.fr
Application: Jeu de Nim
Adresse du site: jeudenim.free.fr
Nom de ce fichier: classes.js
Date de création: mai 2002


**************************
* DEFINITION DES CLASSES *
**************************

CLASSE JEU

Cette classe comporte cinq propriétés:
- etat:
Indique l'etat du jeu, prend la valeur "initial", "joueur joue", "ordinateur joue" ou "fini".
- niveau:
Indique le niveau du jeu, prend la valeur "debutant", "confirme" ou "expert".
- option:
Indique si celui qui prend le dernier pion gagne ou perd la partie, prend la valeur 1 ou 2.
- gains:
Indique le nombre de parties gagnées par le joueur.
- parties:
Indique le nombre total de parties jouées.

Elle comporte une méthode:
- initialiser():
Mettre le jeu dans son état initial.
*/
function CL_jeu() {
  this.etat="initial";
  this.niveau="debutant";
  this.option=1;
  this.gains=0;
  this.parties=0;
  this.initialiser=initialiser_jeu;
}
function initialiser_jeu() {
  this.etat="initial";
  this.coups=0;
}

/*
CLASSE PION

Cette classe comporte trois propriétés:
- rangee:
Indique la rangée où se situe le pion, prend une valeur allant de 0 à 3.
- numero:
Indique le numéro du pion, prend une valeur allant de 0 à n-1, n = nombre de pions par rangée.
- etat:
Indique l'état du pion, prend la valeur "posee", "montree", "choisie" ou "otee".
*/
function CL_pion(rangee,numero) {
  this.rangee=rangee;
  this.numero=numero;
  this.etat="posee";
}

/*
CLASSE RANGEE (DE PIONS)

Cette classe comporte deux propriétés:
- nombre:
Indique le nombre maximal de pions dans la rangée.
- rangee:
Indique le numéro de la rangée.

Elle comporte un tableau d'objets pion.

Elle comporte deux méthodes:
- reste():
Retourne le nombre de pions qui restent dans la rangée.
- choisir(n):
Choisit n pions dans la rangée.
*/
function CL_rangee(nombre,rangee) {
  this.nombre=nombre;
  this.rangee=rangee;
  this.pion=new Array();
  for (var i=0;i<nombre;i++) this.pion[i]=new CL_pion(rangee,i);
  this.reste=reste;
  this.choisir=choisir;
}
function reste() {
  var reste=0;
  for (var i=0;i<this.nombre;i++) if (this.pion[i].etat=="posee") reste++;
  return reste;
}
function choisir(n) {
  var nb_enlevee=0;
  for (var i=0;i<this.nombre;i++) {
    if (this.pion[i].etat=="posee") {
      this.pion[i].etat="choisie";
      nb_enlevee++;
      if (nb_enlevee==n) break;
    }
  }
}

/*
CLASSE TAPIS

Cette classe comporte quatre méthodes:
- initialiser():
Poser tous les pions sur le tapis.
- oter():
Oter du tapis les pions choisis par le joueur ou l'ordinateur.
- verification():
Retourner le nombre de rangées contenant encore des pions.
- selection():
Retourner "correcte", "aucune" ou "incorrecte", selon la sélection effectuée par le joueur.

Elle comporte un tableau d'objets rangees.
*/
function CL_tapis() {
  this.initialiser=tapis_initialiser;
  this.oter=selection_oter;
  this.verification=tapis_verification;
  this.selection=verifier_selection;
  this.rangee=new Array();
  this.rangee[0]=new CL_rangee(1,0);
  this.rangee[1]=new CL_rangee(3,1);
  this.rangee[2]=new CL_rangee(5,2);
  this.rangee[3]=new CL_rangee(7,3);
}
function tapis_initialiser() {
  for (var j=0;j<4;j++) {
    for (var k=0;k<this.rangee[j].nombre;k++) this.rangee[j].pion[k].etat="posee";
  }
}
function selection_oter() {
  for (var j=0;j<4;j++) {
    for (var k=0;k<this.rangee[j].nombre;k++) {
      if (this.rangee[j].pion[k].etat=="choisie") this.rangee[j].pion[k].etat="otee";
    }
  }
}
function tapis_verification() {
  var resultat=0;
  for (var j=0;j<4;j++) if (this.rangee[j].reste()!=0) resultat++;
  return resultat;
}
function verifier_selection() {
  var resultat="aucune";
  for (var j=0;j<4;j++) {
    for (var k=0;k<this.rangee[j].nombre;k++) if (this.rangee[j].pion[k].etat=="choisie") {
      var ligne=j;
      resultat="correcte";
    }
  }
  if (resultat=="correcte") {
    for (var j=0;j<4;j++) {
      for (var k=0;k<this.rangee[j].nombre;k++) {
        if (this.rangee[j].pion[k].etat=="choisie"&&this.rangee[j].pion[k].rangee!=ligne) {
          resultat="incorrecte";
        }
      }
    }
  }
  return resultat;
}

/*
CLASSE COMBINAISON

Cette classe comporte deux propriétés:
- rangee:
Numéro de la rangée dans laquelle il faut enlever des pions.
- nombre:
Nombre de pions à enlever dans la rangee proposée.

Elle comporte deux méthodes:
- choisir(r,s):
Proposer des valeurs pour les propriétés rangee et nombre.
- verifier(r,s):
Retourner "gagnant" ou "indetermine", selon que le jeu soit gagnant ou non.
*/
function CL_combinaison() {
  this.rangee=null;
  this.nombre=null;
  this.choisir=combinaison_choisir;
  this.verifier=verifier;
}
function combinaison_choisir(r,s) {
  // On tente de trouver une solution gagnante.
  var solution="non trouvee";
  var m=new Array();
  for (var j=0;j<4;j++) {
    m[0]=r[0];
    m[1]=r[1];
    m[2]=r[2];
    m[3]=r[3];
    for (var k=1;k<=r[j];k++) {
      m[j]=r[j]-k;
      if (this.verifier(m,s)=="gagnant") {
        this.rangee=j;
        this.nombre=k;
        solution="trouvee";
      }
    }
  }
  // Si une solution gagnante n'est pas trouvée, on joue au hasard.
  if (solution=="non trouvee") {
    this.rangee=Math.floor(4*Math.random());
    while (r[this.rangee]==0) {
      this.rangee=Math.floor(4*Math.random());
    }
    this.nombre=1+Math.floor((r[this.rangee])*Math.random());
  }
}
function verifier(m,s) {
  // Combinaisons gagnantes: 0022-0033-0044-0055-1122-1133-1144-1155-0123-0145-0246-0257-0347-0356
  var v=new Array();
  if (s.option==1) {
    v[0]=1;
    v[1]=3;
    v[2]=5;
  }
  else {
    v[0]=0;
    v[1]=2;
    v[2]=4;
  }
  v[3]=32;
  v[4]=162;
  v[5]=512;
  v[6]=1250;
  v[7]=34;
  v[8]=164;
  v[9]=514;
  v[10]=1252;
  v[11]=98;
  v[12]=882;
  v[13]=1568;
  v[14]=3042;
  v[15]=2738;
  v[16]=2002;
  resultat="indetermine";
  if (s.niveau=="debutant") var nb=2;
  if (s.niveau=="confirme") var nb=10;
  if (s.niveau=="expert") var nb=16;
  for (var j=0;j<=nb;j++) {
    if (Math.pow(m[0],4)+Math.pow(m[1],4)+Math.pow(m[2],4)+Math.pow(m[3],4)==v[j]) resultat="gagnant";
  }
  return resultat;
}

/*
CLASSE COMMENTAIRES

Cette classe comporte six méthodes:
- debut():
Retourne un commentaire pour le début de la partie.
- ordinateur():
Retourne un commentaire lorsque c'est au tour de l'ordinateur de jouer.
- joueur(n):
Retourne un commentaire lorsque c'est au tour du joueur de jouer.
- fin(gagnant):
Retourne un commentaire pour la fin de la partie.
- erreur(n):
Retourne un commentaire lorsque le joueur sélectionne mal les pions.
- option:
Retourne un commentaire lorsque le joueur tente de changer une option en cours de partie.
- quitter():
Retourne un commentaire lorsque le joueur quitte le jeu.
*/
function CL_commentaire() {
  this.debut=commentaire_debut;
  this.ordinateur=commentaire_ordinateur;
  this.joueur=commentaire_joueur;
  this.fin=commentaire_fin;
  this.erreur=erreur_selection;
  this.option=option;
  this.quitter=commentaire_quitter;
}
function commentaire_debut() {
  return "Choisissez les options du jeu \npuis cliquez sur le bouton VALIDER.";
}
function commentaire_ordinateur() {
  var nb=Math.floor(5*Math.random());
  if (nb==0) return "Veuillez patienter, s'il vous plaît.\nJe réfléchis...";
  if (nb==1) return "Veuillez patienter pendant que je joue...";
  if (nb==2) return "C'est à moi de jouer...";
  if (nb==3) return "C'est à mon tour de jouer...";
  if (nb==4) return "Patientez, s'il vous plaît, je réfléchis...";
}
function commentaire_joueur(n) {
  var text="\npuis cliquez sur le bouton RETIRER.";
  if (n==1) return "A vous de jouer:\nDans la dernière rangée d'allumettes,\nsélectionnez celles que vous désirez ôter,"+text;
  if (n==2) return "Vous pouvez jouer:\nDans une des deux rangées d'allumettes,\nchoisissez celles que vous voulez enlever,"+text;
  if (n==3) return "C'est à vous de jouer:\nDans une des trois rangées d'allumettes,\ndésignez celles que vous souhaitez retirer,"+text;
  if (n==4) return "A votre tour de jouer:\nDans une des quatre rangées d'allumettes,\nsélectionnez celles que vous voulez enlever"+text;
}
function commentaire_fin(gagnant) {
  if (gagnant=="joueur") {
    var nb=Math.floor(4*Math.random());
    if (nb==0) return "Bravo, vous avez gagné!\nCliquez sur le bouton REJOUER\npour une nouvelle partie.";
    if (nb==1) return "Toutes mes félicitations, j'ai perdu!\nCliquez sur le bouton REJOUER\npour tenter de gagner encore une fois.";
    if (nb==2) return "Cette fois-ci, vous m'avez battu!\nCliquez sur le bouton REJOUER\npour m'offrir une revanche.";
    if (nb==3) return "Vous avez été le meilleur cette fois-ci!\nCliquez sur le bouton REJOUER\npour rejouer.";
  }
  if (gagnant=="ordinateur") {
    var nb=Math.floor(4*Math.random());
    if (nb==0) return "Navré, mais vous avez perdu!\nCliquez sur le bouton REJOUER\npour essayer de me gagner.";
    if (nb==1) return "Désolé, mais j'ai gagné!\nCliquez sur le bouton REJOUER\npour tenter votre revanche.";
    if (nb==2) return "Cette fois-ci, je vous ai battu!\nCliquez sur le bouton REJOUER,\nne vous découragez pas!";
    if (nb==3) return "J'ai été le meilleur cette fois-ci!\nCliquez sur le bouton REJOUER\npour rejouer.";
  }
}
function erreur_selection(n) {
  if (n==0) return "Attention, vous devez retirer au moins une allumette!";
  if (n==1) return "Attention, sélectionnez vos allumettes dans une seule rangée!";
}
function option() {
  return "Attention, vous ne pouvez pas modifier cette option au cours de la partie!";
}
function commentaire_quitter() {
  var nb=Math.floor(3*Math.random());
  if (nb==0) return "Au revoir. J'espère rejouer avec vous une prochaine fois!";
  if (nb==1) return "J'ai aimé jouer avec vous. Au revoir!";
  if (nb==2) return "Ce fut un plaisir de jouer avec vous. A la prochaine!";
}
