package com.appspot.mscheckers.iACore;
import com.appspot.mscheckers.core.Position;
import com.appspot.mscheckers.core.MoveTable;
public class CPlayer{
char pawn;
char dpawn;
char pawna;
char dpawna;
int pmax = 4;
float pdp = 10; //pourcentage de d�cision des pions
float pdd = 15; //pourcentage de d�cision des dames
//==> 1.5 pion === 1 dame i.e 3 pions = 2 dames
int H = 6; //La profondeur de recherche
int HM = 15; //Hauteur maximale
int HA = 5; //Hateur avant laquelle on peut incrementer H sous certaines conditions
static final long m = (long)Math.pow(2,32);
long seed = (long)(1232132123.0*Math.random());
private int npij; //nombre de pion initial joueur
private int npia; //nombre de pion initial adverse
private int ndij; //nombre de dame initial joueur
private int ndia; //nombre de dame initial adverse
private Position[] pTool = null;
private float[] vTool = null;
Thread th1, th2;
public CPlayer(char pawn, int level)
{
this.pawn = pawn;
this.dpawn = (pawn == 'b')?'B':'W';
this.pawna = ( pawn == 'b')?'w':'b';
this.dpawna = (pawn == 'b')?'W':'B';
this.npij = 0;
this.ndij = 0;
this.npia = 0;
this.ndia = 0;
this.H = level;
}
private int genU(int n)
{
seed = (seed*1232123)%m;
double u = (double)seed/m;
double F = 0;
double p = 1.0/n;
int k = -1;
// System.out.println(" u = "+u);
while(F < u) { F = F+p; k++; }
return k;
}
public Position[] play(char[][] state)
{
Position[][] mt = MoveTable.moveTable(state,this.pawn);
pTool = null;
vTool = null;
if( mt == null ) return null;
int n = mt.length;
//System.out.println("taille : "+n);
//checkers.core.Main.afficher(mt);
if( n == 1 ) return mt[0];
int i,j;
this.npij = 0;
this.ndij = 0;
this.npia = 0;
this.ndia = 0;
for( j = 0; j < 10; j++ ) for( i = 0; i < 10; i++ )
{
if(state[j][i] == pawn) npij++;
if(state[j][i] == pawna) npia++;
if( state[j][i] == dpawn ) ndij++;
if( state[j][i] == dpawna ) ndia++;
}
pTool = new Position[n];
final char[][][] nState = new char[n][10][10];
for(i = 0; i < n; i++ )
{
//System.out.println(" State "+i+"\t"+mt[i][1].getY()+"_"+mt[i][1].getX());
nState[i] = nextState(state, mt[i]);
pTool[i] = new Position(mt[i][0]);
//checkers.core.Main.afficher(nState[i]);
}
int[] id = new int[n];
j = 0;
//boolean th;
float max = 0;
final float eval[] = new float[n];
final float alpha = 0, beta = 100;
final int m = n;
// checkers.core.Main.afficher(mt);
th1 = new Thread(new Runnable()
{
public void run()
{
for( int l = 0; l < m/2; l++ ) eval[l] = alphaBeta(nState[l], alpha, beta, 1, H);
}
});
th1.setPriority(Thread.MAX_PRIORITY);
th1.start();
th2 = new Thread(new Runnable()
{
public void run()
{
for( int l = m/2; l < m; l++ ) eval[l] = alphaBeta(nState[l], alpha, beta, 1, H);
}
});
th2.setPriority(Thread.MAX_PRIORITY);
th2.start();
//System.out.println("Position Y = "+mt[i][1].getY()+" X = "+mt[i][1].getX()+" Valeur : "+mm);
//checkers.core.Main.afficher(cs);
//OOOOOOOOOOOONNNNNNNNNNNN PEUT ARRETER DES QU'ON TROUVE UNE VICTOIRE
try{
th1.join();
th2.join();
}catch(InterruptedException e) { System.out.println("CPlayer ==> error : "+e); }
vTool = eval;
for( i = 0; i < n; i++ )
{
if( vTool[i] > max ) { max = vTool[i]; j = 1; id[0] = i; }
else if( vTool[i] == max ) id[j++] = i;
}
i = id[genU(j)];
//on fixe le tag
//if( mt[i][0] == this.pawn ) this.tag = 0;
//else if( mt[i][0] == this.dpawn ) this.tag = 1;
//System.out.println("id size : "+id.size());
//System.out.println("id size : "+j);
return mt[ i ];
}
public float evaluate2(char[][] state)
{
float mm = 0;
return mm;
}
public float evaluate(char[][] state)
{
int i,j;
int npfj = 0, ndfj = 0,npfa = 0,ndfa = 0;
for( j = 0; j < 10; j++ ) for( i = 0; i < 10; i++ )
{
if(state[j][i] == pawn) npfj++;
if(state[j][i] == pawna) npfa++;
if( state[j][i] == dpawn ) ndfj++;
if( state[j][i] == dpawna ) ndfa++;
}
//System.out.println("npij = "+npij+" npia = "+npia+" npfj = "+npfj+" npfa = "+npfa);
//System.out.println("ndij = "+ndij+" ndia = "+ndia+" ndfj = "+ndfj+" ndfa = "+ndfa);
if( npfa == 0 && ndfa == 0 ) { return 2*(pdp + pdd); }
if( npfj == 0 && ndfj == 0 ) { return 0; }
//J == nombre de pion joueur perdu
float J = (npij - npfj);
//A == nombre de pion adversaire perdu
float A = (npia - npfa);
//JP == nombre de dame joueur perdue
float JP = (ndij - ndfj);
//AP == nombre de dame adversaire perdue
float AP = (ndia - ndfa);
//Mesure le taux de pions perdus
float tpp;
if( A - J >= 0 ) tpp = Math.min( ( A - J )/ pmax, 1 );
else tpp = Math.max( ( A - J )/ pmax, -1 );
//Le taux de dames perdues
float tdp;
if( AP - JP >= 0 ) tdp = Math.min( ( AP - JP )/ pmax, 1 );
else tdp = Math.max( ( AP - JP )/ pmax, -1 );
float mm = (pdp + pdd) + pdp*tpp + pdd*tdp;
//System.out.println("tpp = "+tpp+" tdp = "+tdp+" mm = "+mm);
//checkers.core.Main.afficher(state);
//System.out.println("-------------------------------------------------------------");
return mm;
}
public float minmax(char[][] currentState,int ih, int ht, int h)
{
//System.out.println("ok");
//Si le noeud est une feuille
if( ih == h ) return evaluate(currentState);
float mm1,mm;
Position[][] mt;
int i,n;
//Si le noeud est un noeud joueur
if( ih % 2 == 0)
{
mm = 0;
//checkers.core.Main.afficher(currentState);
mt = MoveTable.moveTable(currentState, pawn);
if( mt == null || mt.length == 0) return evaluate(currentState);
n = mt.length;
if( ih < 7 && take( mt ) == true ) { ht++; h++; }
ih++;
char[][][] nState = new char[n][10][10];
for( i = 0; i < n; i++ ) nState[i] = nextState(currentState, mt[i]);
for( i = 0; i < n; i++)
{
if( ih >= ht )
{
mm1 = evaluate( nState[i]);
if( mm1 <= mm ) continue;
}
mm = Math.max(mm, minmax( nState[i],ih, ht, h));
}
return mm;
}
//Si le noeud est un noeud adversaire
mm = 100; //=> les �valuations sont comprises entre 0 et 100
mt = MoveTable.moveTable(currentState, pawna);
if( mt == null || mt.length == 0) return evaluate(currentState);
n = mt.length;
if( ih < 7 && take( mt ) == true ) { ht++; h++; }
ih++;
char[][][] nState = new char[n][10][10];
for( i = 0; i < n; i++ ) nState[i] = nextState(currentState, mt[i]);
for( i = 0; i < n; i++ )
{
if( ih >= ht )
{
mm1 = evaluate(nState[i]);
if( mm1 >= mm ) continue;
}
mm = Math.min(mm, minmax(nState[i],ih, ht, h));
}
return mm;
}
public float alphaBeta(char[][] currentState, float alpha, float beta, int ih, int h)
{
//System.out.println("ok");
//Si le noeud est une feuille
if( ih == h ) return evaluate(currentState);
float mm;
Position[][] mt;
int i,n;
//Si le noeud est un noeud joueur
if( ih % 2 == 0)
{
mm = 0;
//checkers.core.Main.afficher(currentState);
mt = MoveTable.moveTable(currentState, pawn);
if( mt == null || mt.length == 0) return evaluate(currentState);
n = mt.length;
if( ih < HA && take( mt ) == true ) h++;
else if( h < HM && n == 1 ) h++;
ih++;
char[][][] nState = new char[n][10][10];
for( i = 0; i < n; i++ ) nState[i] = nextState(currentState, mt[i]);
for( i = 0; i < n; i++)
{
mm = Math.max(mm, alphaBeta( nState[i],alpha, beta, ih, h));
if( mm >= beta ) return mm;
alpha = Math.max(alpha, mm);
}
return mm;
}
//Si le noeud est un noeud adversaire
mm = 100; //=> les �valuations sont comprises entre 0 et 100
mt = MoveTable.moveTable(currentState, pawna);
if( mt == null || mt.length == 0) return evaluate(currentState);
n = mt.length;
if( ih < HA && take( mt ) == true ) h++;
else if( h < HM && n == 1 ) h++;
ih++;
char[][][] nState = new char[n][10][10];
for( i = 0; i < n; i++ ) nState[i] = nextState(currentState, mt[i]);
for( i = 0; i < n; i++ )
{
mm = Math.min(mm, alphaBeta(nState[i],alpha, beta, ih, h));
if( mm <= alpha ) return mm;
beta = Math.min(beta, mm );
}
return mm;
}
public boolean take(Position[][] mt)
{
if( mt[0].length > 2 ) return true;
for( int i = 0; i < mt.length; i++ )
if( Math.abs( mt[i][0].getX() - mt[i][1].getX() ) == 1 ) return false;
return true;
}
public char[][] nextState(char[][] state, Position[] move)
{
char st[][] = new char[10][10];
for(int j = 0; j < 10; j++ ) for(int i = 0; i < 10; i++) st[j][i] = state[j][i];
char c = st[move[0].getY()][move[0].getX()];
st[move[0].getY()][move[0].getX()] = 'v';
Position p;
int n = move.length-1;
if( (c == 'W')?true:((c == 'B')?true:false) )
for(int i = 0; i < n; i++ )
{
p = Position.pawnBetween(move[i],move[i+1],state);
if( p != null ) st[p.getY()][p.getX()] = 'v';
}
else
for(int i = 0; i < n; i++ ) st[(move[i].getY()+move[i+1].getY())/2][(move[i].getX()+move[i+1].getX())/2] = 'v';
if(move[n].getY() == 0 && c == 'w') st[move[n].getY()][move[n].getX()] ='W';
else if(move[n].getY() == 9 && c == 'b') st[move[n].getY()][move[n].getX()] ='B';
else st[move[n].getY()][move[n].getX()] = c;
//System.out.println("P1 : Y = "+p1.getY()+" X = "+p1.getX());
//System.out.println("P2 : Y = "+p2.getY()+" X = "+p2.getX());
return st;
}
public Position[] getPTool(){ return pTool; }
public float[] getVTool(){ return vTool; }
/*
public static void main(String[] args){
//CheckersModel dm = new CheckersModel();
//String t="";
CPlayer cp = new CPlayer('w',8);
char[][] cs = core.CheckerModel.checkerBoard();
//for(int j = 0; j < 10; j++ ) for(int i = 0; i < 10; i++ ) if(cs[j][i] == 'b' || cs[j][i] == 'w') cs[j][i] = 'v';
//cs[1][4] = 'b';
//cs[0][7] = 'b';
//cs[3][8] = 'b';
//cs[2][3] = 'b';
//cs[9][2] = 'B';
//cs[2][9] = 'w';
//cs[2][9] = 'w';
//cs[6][7] = 'w';
core.Main.afficher(cs);
Position[] mt = cp.play(cs);
core.Main.afficher(mt);
//System.out.println("k = ");
}
*/
}