The beat goes on. Sigh. I appreciate everyone's patience. OK, I'm trying this from a slightly different angle. I've written another engine class, as small as possible. This is it in its entirety, except for move generation, which is in another class. I've tried to follow Bruce Moreland's model as closely as possible. I've been focusing on the WAC positions, and Reinfeld's 1001 checkmates.
The algorithm works with checkmaye combinations very nicely, but is out to lunch on material advantage,
Only one question, and I think I have it covered. Moreland's alphaBeta function returns an eval (alpha), so it must be there there is another non-recursive "root-search" which determines available moves, then iterates through the list evaluating each move recursively by calling alphaBeta for each possible engine move.
anyways, I have not attempted to deal with what happens if the engine loses. This is just for WAC positions, as long as they don't involve the possibility of stalemate or promotion.
Like I say, forced mate is handled fine, material advantage is mishandled, and I really have no idea why. If need be, I can provide for test positions a list of legal moves along with the eval for each. Once I get this part working, then I'll deal with promotion and computer losing.
anyways, here's Moreland's alphabeta page
http://web.archive.org/web/200404200223 ... habeta.htm
and here's my engine class. I'm led to understand it is an example of "fail-hard" alphabeta.
Code: Select all
import java.util.*;
public class Engine4 {
private static Random rand = new Random();
Output output;
int ply;
boolean think = false;
boolean diagnostics = false;
public Engine4( int ply ) {
this.ply = ply;
}
public Engine4( Output output, int ply ) {
this.output = output;
this.ply = ply;
}
/*********************************************************************************/
public Move getBestMove( String pStr ) {
CMove[] list1 = possibleMoves(pStr);
int alpha = -10000;
int beta = 10000;
for( CMove cm : list1 ) {
if( diagnostics ) output.append( Utils.longAlg( cm.i, cm.j ) );
cm.eval = -alphaBeta( cm.pStr, ply-1, -beta, -alpha );
if( cm.eval > alpha ) alpha = cm.eval;
if( diagnostics ) output.append( " " +cm.eval +"\n" );
if( cm.eval == 10000 ) {
ply -=2;
return new Move( pStr.charAt(cm.i), cm, "forced mate");
}
}
ArrayList<CMove> list2 = new ArrayList<CMove>();
// extract the moves whose eval == maximum
for( CMove cm : list1 ) {
if( cm.eval == alpha ) list2.add(cm);
}
// select randomly from the list of moves that have the maximum eval.
int select = rand.nextInt( list2.size() );
CMove cm = list2.get(select);
Move m = new Move( pStr.charAt(cm.i), cm, "normal");
return m;
}
/*********************************************************************************/
private int alphaBeta( String pStr, int depth, int alpha, int beta ) {
if( depth == 0 ) return evaluate( pStr );
int best = -10000;
int val;
int i,j;
String p1Str;
boolean white = pStr.charAt(64) == 'w';
int[][] candidates = Utils.getCandidates( pStr );
for( int m=0; m<candidates.length; m++ ) {
i = candidates[m][0];
j = candidates[m][1];
p1Str = Utils.checkMove( pStr, i, j );
if( p1Str.equals("false") ) continue;
val = -alphaBeta( p1Str, depth-1, -beta, -alpha );
if( val >= beta ) return beta;
if( val > alpha ) alpha = val;
}
return alpha;
}
/*********************************************************************************/
// a non-recursive method which returns a list of legal CMove objects.
CMove[] possibleMoves( String pStr ) {
ArrayList<CMove> mList = new ArrayList<CMove>(40);
CMove cm;
String p1Str;
int i, j;
boolean promoFlag;
boolean white = ( pStr.charAt(64) == 'w' );
int[][] cand = Utils.getCandidates( pStr );
for( int m=0; m<cand.length; m++ ) {
i = cand[m][0];
j = cand[m][1];
p1Str = Utils.checkMove( pStr, i, j );
if( p1Str.equals("false") ) continue;
mList.add( new CMove(i, j, p1Str) );
}
return mList.toArray( new CMove[mList.size()] );
}
/*********************************************************************************/
// the method for material evaluation of the position.
public int evaluate( String pStr ) {
int wmat = 0, bmat = 0;
char p;
for( int i=0; i<64; i++ ) {
p = pStr.charAt(i);
if( p == '1' ) continue;
switch(p) {
case 'p': bmat += 10; break;
case 'P': wmat += 10; break;
case 'r': bmat += 50; break;
case 'R': wmat += 50; break;
case 'n': bmat += 25; break;
case 'N': wmat += 25; break;
case 'b': bmat += 30; break;
case 'B': wmat += 30; break;
case 'q': bmat += 90; break;
case 'Q': wmat += 90; break;
}
}
return ( pStr.charAt(64) == 'w' ) ? ( bmat - wmat ) : ( wmat - bmat );
}
/*********************************************************************************/
}