<!-- 
//----------------------------------------------------------------------
// Auteur : Frédéric MAIRE (c) 1998 All right reserved
// Dec 1998 creation
// Dec 1998 : IA 1.0 avec pattern pour heuristique
// Dec 1998 : IA 1.1 avec evaluation du coup adverse en retour
// Dec 1998 : IA 1.2 avec evaluation du coup adverse sur sa position
//----------------------------------------------------------------------

nbImg = 1;  // nombre d'images avant le plateau

var imgCPion;
var imgPion;
var imgVic;
var imgThink;
var game;

var heuris0 = new Array (2,2,5, 2,2,2, 5,2,2,  1,1,1, 1,1,1, 1,1,1,  500,200,500, 3,3,3, 500,300,100000 );
var heuris1 = new Array (1,0,1, 0,0,0, 2,0,100, 0,0,0, 0,0,0, 0,0,0, 3,0,200, 0,0,0, 1000,0,100000 );

// - - - - - - - - - - - - - - - -

// Chargement des images du jeu
function ChargeImg() {
    imgCPion = new Array(3);
    imgPion = new Array(3);
    for (i=0; i<3; i++) {
        imgCPion[i] = new Image(56,56);
        imgCPion[i].src = "cpion" + eval(i) + ".gif";
        imgPion[i] = new Image(56,56);
        imgPion[i].src = "pion" + eval(i) + ".gif";
    }
    imgVic = new Array(4);
    for (i=0; i<4; i++) {
        imgVic[i] = new Image(200,50);
        imgVic[i].src = "vic" + eval(i) + ".gif";
    }
    imgThink = new Array(8);
    for (i=0; i<8; i++) {
        imgThink[i] = new Image(48,48);
        imgThink[i].src = "think" + eval(i) + ".gif";
    }
}

ChargeImg();

//--------------------
// objects
//--------------------

function show_props(obj, obj_name) { 
    var result = "" 
    for (var i in obj) 
        result += obj_name + "." + i + " = " + obj[i] + "\n" 
    return result; 
} 

// - - - - - - - - - - - - - - - -
//  PositionClass
// - - - - - - - - - - - - - - - -

function CalculatePosition( pos, jou, num) {
// calculate the future position in "this" for
// a play in (jou,num) on position "pos"
// (no valid move => fut=pos)

    this.Copy( pos);

    if (this.IsValidMove( jou, num)) {
      // le pion tombe tant que du vide
      j = 6;
      while ((this.plat[num][j-1] == 0) && (j>0)) j--;
      // bouge le pion
      this.plat[num][j] = jou+1;
    }
}

function ExistCaseDir( x, y, dirx, diry, n) {
  return ( ((x+n*dirx)>=0) && ((y+n*diry)>=0) && ((x+n*dirx)<7) && ((y+n*diry)<6) );
}
// return appartenance adversaire=>1 partenaire=>2
function VirtualCaseDir( pos, x, y, dirx, diry, n, jou) {
var val;
  if (ExistCaseDir( x, y, dirx, diry, n)) {
    val = pos.plat[x+n*dirx][y+n*diry];
    if (val==0) return 0;
    else return (val==(jou+1))?2:1;
  } else {
    return 1; // case qui n'existe pas consideree comme bloquee
  }
}
function EvaluateDirectionPosition( jou, x, y, dirx, diry) {
var idx = 0;
var ajou = (jou==0)?1:0; // adversaire

  if (this.plat[x][y] == jou+1) {
	if (VirtualCaseDir( this, x, y, dirx, diry, -1) == 2) {
        return 0; // ne compte pas deux fois
      } else {
        idx = 9 * VirtualCaseDir( this, x, y, dirx, diry, 1, jou)
            + 3 * VirtualCaseDir( this, x, y, dirx, diry, 2, jou)
            + 1 * VirtualCaseDir( this, x, y, dirx, diry, 3, jou);
        if (VirtualCaseDir( this, x, y, dirx, diry, -1)== 1) { 
          return heuris1[idx]; // case precedente a l'adversaire
        } else { 
          return heuris0[idx]; // case precedente vide
        }
      }
  } else {
    // pas d'evaluation si la case n'appartient pas au joueur considere
    return 0;
  }
}

function EvaluatePosition( jou) {
var som = 0;
//var ajou = (jou==0)?1:0; // adversaire

    // calcul le nombre de ligne de longueur differente pour chaque joueur
    for (i=0; i<7; i++) {
    for (j=0; j<6; j++) {
      som += this.EvaluateDirection( jou, i, j,  1,  0);
      som += this.EvaluateDirection( jou, i, j,  1, -1);
      som += this.EvaluateDirection( jou, i, j,  0, -1);
      som += this.EvaluateDirection( jou, i, j, -1, -1);
    }}

//alert( eval(som)+" $ "+ eval(this.lig[0])+":"+eval(this.lig[1])+":"+eval(this.lig[2])+":"+eval(this.lig[3])+":"+eval(this.lig[4]) );
    return som;
}
function IsValidMovePosition( jou, num) {
    return this.plat[num][5] == 0;
}
function CalculateEndStatusPosition() {
var som0, som1;
  // de base on continue
  this.endStatus = 0;
  // soit tout plein
  if (this.plat[0][5]!=0 && this.plat[1][5]!=0 && this.plat[2][5]!=0  && this.plat[3][5]!=0
   && this.plat[4][5]!=0 && this.plat[5][5]!=0 && this.plat[6][5]!=0) {
    this.endStatus = 3;
  }
  // soit un gagnant
  som0 = this.Evaluate( 0);
  if (som0 >= 100000) this.endStatus = 1;
  som1 = this.Evaluate( 1);
  if (som1 >= 100000) this.endStatus = 2;
}
function CopyPosition( pos) {
    for (var i=0; i<7; i++) {
    for (var j=0; j<6; j++) {
        this.plat[i][j] = pos.plat[i][j];
        this.plat[i][j] = pos.plat[i][j];
    }}
    this.endStatus = pos.endStatus;
}
// generate a start position
function SetStartPosition() {
    for (var i=0; i<7; i++) {
    for (var j=0; j<6; j++) {
        this.plat[i][j] = 0;
    }}
    this.endStatus = 0;
}
function PositionClass() {
    // attributes
    // le plateau 0=vide 1=ordi 2=joueur (=> jou+1)
    this.plat = new Array(7); 
    for (var i=0; i<7; i++) this.plat[i] = new Array(6);
    // init attributes
    for (var i=0; i<7; i++) {
    for (var j=0; j<6; j++) {
        this.plat[i][j] = 0;
    }}
    this.endStatus = 0; // 0=play 1=ordi_win 2=play_win 3=draw
    // methods
    this.Copy = CopyPosition;
    this.EvaluateDirection = EvaluateDirectionPosition;
    this.Evaluate = EvaluatePosition;
    this.Calculate = CalculatePosition;
    this.IsValidMove = IsValidMovePosition;
    this.SetStart = SetStartPosition;
    this.CalculateEndStatus = CalculateEndStatusPosition;
}

// - - - - - - - - - - - - - - - -
//  GameClass
// - - - - - - - - - - - - - - - -

function CalculateEndStatusGame() {
  this.actPos.CalculateEndStatus();
  this.isEnd = (this.actPos.endStatus != 0);
}
function PlayAIGame( jou) {
var ajou = (jou==0)?1:0;
var bestnum, bestnumj;
var num, numj, inum, inumj;
var posexa = new Array (3,2,4,1,5,0,6);
    bestnum = -999999; inum = -1;
    // recherche la meilleure position 
    for (var n=0; n<7; n++) {
    if (this.actPos.IsValidMove( jou, posexa[n])) {
      this.futPos.Calculate( this.actPos, jou, posexa[n]);
      num = this.futPos.Evaluate( jou, true);
      // si on gagne, l'adversaire est out, donc pas la peine de s'attrister sur son sort
      // et puis si le nouveau coup, est de toute facon plus pourri, on s'arrete aussi
      bestnumj = -1;
      if ((num < 100000) && (num > bestnum)) {      
        // evalue le coup en retour de l'adversaire
        for (var nj=0; nj<7; nj++) {
          Think( true, n, nj);
          this.futPos2.Calculate( this.futPos, ajou, posexa[nj]);
//this.RepaintPosition( this.futPos2);
          numj = this.futPos2.Evaluate( ajou);
          // tient compte de la valeur de la position pour le joueur IA
          numj += this.futPos2.Evaluate( jou);
//alert( "JJ "+eval(posexa[n])+" o="+eval(num)+" j="+eval(numj)+"/"+eval(posexa[nj])+" mj="+eval(bestnumj)+"/"+eval(posexa[inumj]) );
          if (numj > bestnumj) { 
            bestnumj = numj;
            inumj = posexa[nj];
          }
          if (bestnumj >= 100000) { 
            // sur la proposition de l'IA l'adversaire gagne a coup sur !
            break;
          }
        } 
//alert( eval(posexa[n])+" o="+eval(num)+" j="+eval(bestnumj)+"/"+eval(inumj) );
      }
      num = num - bestnumj;
      if (num > bestnum) {
         bestnum = num;
         inum = posexa[n];
//this.RepaintPosition( this.futPos);
      }   
    }
    }
    Think( false, 0, 0);
    if (inum != -1) {
      this.Play( jou, inum);
    }
}
function PlayGame( jou, num) {
    if (this.actPos.IsValidMove( jou, num)) {
      // let the pawn fall
      FallingPawn( jou, num, 5);
      // calculate pos
      this.futPos.Calculate( this.actPos, jou, num);
      this.actPos.Copy( this.futPos);
    } else {
      // no valid move
      alert( "No Valid Move");
    }
    this.CalculateEndStatus();
    game.Repaint();
    if (this.isEnd) EndGame();
}
function RepaintGame() {
    for (var i=0; i<7; i++) {
    for (var j=0; j<6; j++) {
      document.images[nbImg+7+i+(5-j)*7].src = imgPion[ this.actPos.plat[i][j] ].src;
    }}
}
function RepaintPositionGame( pos) {
    for (var i=0; i<7; i++) {
    for (var j=0; j<6; j++) {
      document.images[nbImg+7+i+(5-j)*7].src = imgPion[ pos.plat[i][j] ].src;
    }}
}
function SetNewGame() {
    this.actPos.SetStart();
    this.futPos.SetStart();
    this.isEnd = false;
    EndGame(); // pour le message victoire
}
function GameClass() {
    // attributes
    this.name = "PUISSANCE4";
    this.actPos = new PositionClass();
    this.futPos = new PositionClass(); // pour coup IA
    this.futPos2 = new PositionClass(); // pour coup retour joueur
    this.evalPosIA = new Array(7);  
    this.isEnd = false;
    // methods
    this.CalculateEndStatus = CalculateEndStatusGame;
    this.SetNew = SetNewGame;
    this.Repaint = RepaintGame;
    this.RepaintPosition = RepaintPositionGame;
    this.PlayAI = PlayAIGame;
    this.Play = PlayGame;
}


// - - - - - - - - - - - - - - - -

function FallingPawn( jou, num, haut) {
  // retire le precedent
  if (haut!=5) {
    document.images[nbImg+7+num+(5-haut-1)*7].src = imgPion[0].src;
  }
  // le suivant
  document.images[nbImg+7+num+(5-haut)*7].src = imgPion[ jou+1 ].src;
  // continue a tomber
  if (haut>0) {
  if (game.actPos.plat[num][haut-1]==0) {
//    setTimeout( 'FallingPawn('+jou+','+num+','+haut-1+');', 10);
//  document.images[nbImg+7+num+(5-haut)*7].src = imgPion[0].src;
    FallingPawn( jou, num, haut-1);
  }}
}

// - - - - - - - - - - - - - - - -

function Init() {
    game = new GameClass();
//alert( show_props( game, "GameClass"));
//alert( show_props( game.actPos, "PositionClass"));
    game.SetNew();
    game.Repaint();
}

function PlayFirst() {
    NewGame();
//    game.PlayAI(0);
    game.Play( 0, 3);
}
function JouePlayer( jou, num) {
var valid;
  if (!game.isEnd) {
    if (jou==1) {
        valid = game.actPos.IsValidMove(jou,num);
        if (valid) {
            game.Play(jou,num);
            if (!game.isEnd) { game.PlayAI(0); }
        }
    }
  }
}
function Joue( num) {
  OverOutCase( num);
  JouePlayer( 1, num);
}
function NewGame() {
    game.SetNew();
    game.Repaint();
}
function EndGame() {
  document.images["victoire"].src = imgVic[ game.actPos.endStatus ].src;
}

// - - - - - - - - - - - - - - - -

function OverCase( n) {
  document.images[nbImg+n].src = imgCPion[2].src;
}
function OverOutCase( n) {
  document.images[nbImg+n].src = imgCPion[0].src;
}

function Think( act, num0, num1) {
  if (act) {
    document.images["think0"].src = imgThink[num0].src;
    document.images["think1"].src = imgThink[num1].src;
  } else {
    document.images["think0"].src = imgThink[7].src;
    document.images["think1"].src = imgThink[7].src;
  }
} 

// - - - - - - - - - - - - - - - -

// -->

