Commit 88bb8def authored by Jose G. López's avatar Jose G. López
Browse files

Imported Upstream version 25

parent ee4b9b8f
......@@ -274,3 +274,36 @@ XXII Better ICS whispering, it sends only one info per move. Bugfix in
the first finger line on ICS, it shows version, size of hashtable,
and sizes of the opening books. Bugfix in benchmark, the resulting
number was incorrect on machines that can do over 70kNps.
XXIII Xboard protocol version 2 compatibility, including the periodic
20141020 updates feature. New -n commandline option to limit nodes per
second. New -z commandline option to randomize root moves. Easy
levels now don't play instantly, but use time. DrawScore (contempt
factor) adjusted in endgames towards positive values to avoid playing
dead draws like KRKR. Minor engine fixes: Simplified rootsearch,
the aspiration window implementation was not good, for now replaced
with standard PVS. Temporarily disabled static eval cache as the
implementation was not correct. Other minor bugfixes.
Known issues: Warnings in io.c. Command 'setboard' moves the Counter
variable, which then cripples the 'history' command output. Command
'setboard' chokes on unexpected input. These issues are only
apparent in commandline and should never occur via a GUI - leaving
the fix to a future release.
XXIV Xboard protocol - 'memory' command support. New file phalanx.eng to
20141224 support the new Xboard automatic engine load. More log messages.
Late move reductions with move count based pruning. Small but
important changes in the static evaluation that improve endgame play:
Passed pawn, rook mobility, knight mobility. Default contempt factor
changed from -20 to -10. Fixed tournament timecontrols. Positional
learning is now off by default. Tweaked polling input timeslice to
better handle rapid changes in analyze mode. Fixed GCC warnings.
XXV Better time management to use more time if the best move changed
20160501 recently. Search improvements: Added simple ProbCut, tuned null move
and LMR, simplified check evasion extension. Static evaluation bug
fixes, several of them submitted by Fabrice Lecouvey, thanks. New
parameter to root moves randomization, it can now be limited
to first N moves of the game. New opening book generated from
KingBase Lite 03/2016 (http://www.kingbase-chess.net/).
makefile
\ No newline at end of file
Phalanx is a chess playing program
Copyright (c) 1997, 1998, 1999, 2000 Dusan Dobes
Copyright (c) 1997, 1998, 1999, 2000, 2014 Dusan Dobes
LICENSE AND WARRANTY
......@@ -20,15 +20,8 @@ LICENSE AND WARRANTY
WHERE TO GET PHALANX
- http://www.crosswinds.net/~dobes/phalanx/
- http://sourceforge.net/projects/phalanx/
- ftp://sunsite.unc.edu/pub/Linux/games/strategy/ (Only sources)
Sunsite is well maintained archive with lots of mirrors, but it's dedicated
to Linux. If you want to try Win32 binary or bigger secondary opening book
try following site, it has both sources and Win32 binaries plus opening books
largebook.zip and hugebook.zip:
- ftp://ftp.math.muni.cz/pub/math/people/Dobes/
- http://www.gambitsoft.com/sharee.htm (Only Win32 binaries)
- http://www.cent.co.yu/chess/free.htm (Only Win32 binaries)
Please let me know if there are others, i will update this list.
Feel free to put Phalanx on your ftp site.
......@@ -62,7 +55,6 @@ MORE ABOUT INTERFACE
I'm trying to write an interface that fits following three requirements:
- Xboard compatibility. For best results, get the latest version of Xboard.
(http://www.research.digital.com/SRC/personal/Tim_Mann/chess)
- shell-like interface that allows running commands in a batch. It's very
useful for testing. Example: look into the file test.fin. It's a set
of chess problems and solutions. You can simply send this file to
......@@ -110,17 +102,31 @@ COMMAND LINE OPTIONS
standard input and polling input makes it stop thinking after almost
zero seconds on each position.
-b <+/-> opening book default: on
-l <+/-> learning on/off default: on
-l <+/-> learning on/off default: off
-r <resign value in centipawns> default: 0 (no resigning)
-e <easy level 0...100> default: 0 (best play)
1 is the hardest and 100 is the easiest easy level. Phalanx tries to
-e <easy level 0...99> default: 0 (best play)
1 is the hardest and 99 is the easiest easy level. Phalanx tries to
emulate human-like blunders, the higher the number the more blunders it
plays. It also adds more randomness with the easy levels, repeating
games should be impossible. Easy levels set hashtable size to zero,
pondering and learning to off. Phalanx responds almost immediatelly to
opponent's move. Node count is used instead of the time, so appropriate
levels should give the same strength even on different machines
(e.g. 486 == Pentium-III).
pondering and learning to off. Since version XXIII, Phalanx uses
the time normally, it does not respond immediatelly. NPS is lowered
to 100-300, unless overriden by the -n agrument. Root moves randomizing
is used here as well, between 10 to 60 centipawns, unless overriden
by the -z argument.
-z <random evaluation in centipawns> default: 0 (best play)
Randomize play. Add pseudo-random values to root moves evaluations.
The numeric value limits the random range, the interval of random
evaluations to be added is [-N/2 ... N/2].
-z <random evaluation in centipawns>:<N>
Like above, but only randomize first N moves. This is to avoid repeating
lines in opening, while keeping almost the same playing strength. For
example, -z 20:10 will randomize first 10 moves in the game by
20 centipawns.
-n <nodes per second> default: 0 (no limit)
Limits the speed to weaken the engine and to use less resources: The
speed of the machine does not matter here, it uses usleep() during
the search, so with low NPS it does not raise the machine load.
-v
Print version and exit.
-P <primary book directory>
......@@ -167,9 +173,12 @@ COMMAND LINE OPTIONS
50 gives lots of variability and maybe dubious moves, 100 gives almost
no variability and only the highest valued moves. Default is 80.
Note that the book creation does not work with DOS end-of-lines in the PGN
input, just use dos2unix filter if needed.
Examples: phalanx -c+ -s+ -o - -x- -f 60 -t4000
xboard -fcp "phalanx -r800"
xboard -fcp 'phalanx -e 100'
xboard -fcp 'phalanx -e 99'
ASCII INTERFACE COMMANDS
......@@ -260,5 +269,5 @@ INSIDE THE MACHINE
AUTHOR
Dusan Dobes, dobes@math.muni.cz
Dusan Dobes
......@@ -60,14 +60,20 @@ void printit(int x)
printf("%8i%10i%7i%%",
games,positions,I*100/Asize);
fflush(stdout);
#if defined(__GNUC__) && !defined(__MINGW32__)
signal(SIGALRM,printit); alarm(5);
#endif
}
void compress(void)
{
int i1, i2;
printit(0);
#if defined(__GNUC__) && !defined(__MINGW32__)
alarm(0);
#endif
printf("\nsorting buffer ............ ");
qsort( A, I, sizeof(tb), bsortkey );
......@@ -134,13 +140,15 @@ void compress(void)
* joined to the first one and reopen */
fclose(tb1); fclose(tb2);
remove("rbook.phalanx");
rename("rbook.phalanx.tmp","rbook.phalanx");
printf("done\n");
}
I=0;
#if defined(__GNUC__) && !defined(__MINGW32__)
alarm(5);
#endif
}
int bpoints, wpoints;
......@@ -182,13 +190,6 @@ int addmove(char *move)
{ static tmove m[256];
tmove * mf;
static int n;
int i;
int p=PAWN+Color;
for(i=2;i!=7;i++) if(piece[i]==move[0]) p=16*i+Color;
if( move[0]=='O' )
{ p=KING+Color;
if(move[3]=='-') { if(Color==WHITE){} }
}
generate_legal_moves( m, &n, checktest(Color) );
if( (mf=sandex(move,m,n)) != NULL )
......@@ -216,9 +217,9 @@ int addmove(char *move)
void parsegame(void)
{ register int c='*';
unsigned char m[128];
/*unsigned*/ char m[128];
int i;
setfen("rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/w");
setfen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
while( c!='[' && c!=EOF && Counter < MaxBookPly )
{ while( (c=getchar()) != '.' && c!=EOF )
if(c=='{')
......@@ -334,13 +335,18 @@ int bcreate( int argc, char ** argv )
puts( "-----------------------------");
puts( " games positions buffer%");
puts( "-----------------------------");
#if defined(__GNUC__) && !defined(__MINGW32__)
signal(SIGALRM,printit); alarm(5);
#endif
while( findgame() )
{ parsegame(); games++; }
printf("end of file, parsed %i positions in %i games\n",positions,games);
if( games == 0 )
{ puts("opening book not created"); return 0; }
compress(); alarm(0);
compress();
#if defined(__GNUC__) && !defined(__MINGW32__)
alarm(0);
#endif
stage_2:;
......@@ -357,7 +363,7 @@ int bcreate( int argc, char ** argv )
stat("rbook.phalanx",&fs); fsize = fs.st_size/sizeof(tb);
printf("writing book ");
printf("rbook records = %i, writing book ", fsize);
while(!feof(tb1))
{
......
......@@ -181,7 +181,7 @@ int parsemove( char *inp, tmove *m, int n )
/* binary book */
int sbookmoves( int *moves, int *values, tmove *m, int n )
{
int index, i;
int idx, i;
int64 first, last=0, middle=0;
unsigned fkey, lkey;
unsigned pos;
......@@ -248,7 +248,7 @@ printf("[%i %i %i %i] [%08X %08X]\n",
{ middle ++; pos = G[Counter].hashboard; }
/*** Position found in book! ***/
index=0;
idx=0;
if( fseek(f,middle*6+4,SEEK_SET)!=0 ) return -1;
while( middle<booksize && pos==G[Counter].hashboard )
{
......@@ -256,12 +256,12 @@ printf("[%i %i %i %i] [%08X %08X]\n",
myfread( &sm, sizeof(unsigned short), f );
for( i=0; i!=n; i++ ) if( sm == smove(m+i) )
{ moves[index]=i; values[index]=100; index++; }
{ moves[idx]=i; values[idx]=100; idx++; }
myfread( &pos, sizeof(unsigned), f );
}
return index;
return idx;
}
......@@ -275,7 +275,7 @@ printf("[%i %i %i %i] [%08X %08X]\n",
int bookmoves( int *moves, int *values, tmove *m, int n )
{
char s[256], p[256];
int index, i;
int idx, i;
long booksize; /* filesize in bytes */
FILE *f;
......@@ -288,21 +288,21 @@ int bookmoves( int *moves, int *values, tmove *m, int n )
{ return -1; }
/*** Position found in book! ***/
index=0;
idx=0;
for(i=0; s[i]!='\n'; i++)
{
int pm;
while(s[i]!=' ' && s[i]!='\n')
{
if(s[i]=='!' && index) values[index-1]+=100;
if(s[i]=='!' && idx) values[idx-1]+=100;
i++;
}
if(s[i]=='\n') break; i++; if(s[i]=='\n') break;
if( (pm=parsemove(&s[i],m,n)) != -1 )
{ moves[index]=pm; values[index]=100; index++; }
{ moves[idx]=pm; values[idx]=100; idx++; }
}
return index;
return idx;
}
......@@ -313,17 +313,17 @@ int bookmoves( int *moves, int *values, tmove *m, int n )
*/
int bookmove( tmove *m, int n )
{
int moves[80], values[80], index;
int moves[80], values[80], idx;
int foundtxt=0;
index = bookmoves(moves,values,m,n);
if( index <= 0 ) index = sbookmoves(moves,values,m,n);
idx = bookmoves(moves,values,m,n);
if( idx <= 0 ) idx = sbookmoves(moves,values,m,n);
else
{
#ifdef SHOWDUPS
int moves2[80]; int values2[80], index2;
index2 = sbookmoves(moves2,values,m,n);
if( index2>=1 && index>=1 && Counter>8 )
int moves2[80]; int values2[80], idx2;
idx2 = sbookmoves(moves2,values,m,n);
if( idx2>=1 && idx>=1 && Counter>8 )
{
char p[256]; int i;
postr(p);
......@@ -331,7 +331,7 @@ int bookmove( tmove *m, int n )
printboard(NULL);
puts(p);
printf(" 0 0 0 0 book2 ");
for( i=0; i!=index2; i++ )
for( i=0; i!=idx2; i++ )
if( i==0 || moves2[i-1]!=moves2[i] )
{ printm( m[moves2[i]], NULL ); }
puts("");
......@@ -340,40 +340,43 @@ int bookmove( tmove *m, int n )
foundtxt=1;
}
if( index > 0 )
if( idx > 0 )
{
int ii, sumvalues=0, rn;
for( ii=0; ii!=index; ii++ )
for( ii=0; ii!=idx; ii++ )
{ sumvalues += values[ii]; }
rn = rand()%sumvalues;
sumvalues = 0;
for( ii=0; ii!=index; ii++ )
for( ii=0; ii!=idx; ii++ )
{ sumvalues += values[ii]; if( sumvalues >= rn ) break; }
if( Flag.post )
{ int i;
char s[128];
if( Flag.xboard )
sprintf(s," 0 0 0 0 book");
sprintf(s," 0 0 0 0 (");
// sprintf(s," 0 0 0 0 book");
else
sprintf(s,"Book moves ");
if( foundtxt ) sprintf(s+strlen(s),"1 ");
else sprintf(s+strlen(s),"2 ");
for( i=0; i!=index; i++ )
for( i=0; i!=idx; i++ )
{ printm( m[moves[i]], s+strlen(s) ); }
// hacked by S.A. to show bookX at end of line
if( foundtxt ) sprintf(s+strlen(s),", book1)");
else sprintf(s+strlen(s),", book2)");
sprintf(s+strlen(s),"\n");
printf(s);
printf("%s",s);
if( Flag.log!=NULL && Flag.ponder<2 )
{
char sm[64];
if(Flag.xboard) fprintf(Flag.log,s+26);
else fprintf(Flag.log,s);
if(Flag.xboard) fprintf(Flag.log,"%s",s+26);
else fprintf(Flag.log,"%s",s);
fprintf(Flag.log," selected move ");
printm( m[moves[ii]], sm );
fprintf(Flag.log,sm);
fprintf(Flag.log,"\n");
fprintf(Flag.log,"%s\n",sm);
}
}
return ( moves[ii] );
......@@ -420,7 +423,7 @@ if( att != 0 && Eco!=NULL )
(peco+seco)->point=ftell(Eco)-1;
while( (c=getc(Eco))!=']' ) if( c==EOF ) goto doneinit;
if( c==EOF ) goto doneinit;
setfen("rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/w");
setfen(initialpos);
for(;;)
{
msi=0;
......@@ -447,7 +450,7 @@ if( att != 0 && Eco!=NULL )
doneinit:;
printf(" parsed %i ECO records\n",seco);
att=2;
setfen("rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/w");
setfen(initialpos);
}
if( Counter>0 && att>1 )
......@@ -470,8 +473,8 @@ if( att != 0 && Eco!=NULL )
fseek(Eco,text,SEEK_SET);
fgets(t,126,Eco);
t[127]='\0';
c=index(t,'['); if(c!=NULL) *c = ' ';
c=rindex(t,']'); if(c!=NULL) *c = '\0';
c=strchr(t,'['); if(c!=NULL) *c = ' ';
c=strrchr(t,']'); if(c!=NULL) *c = '\0';
puts(t);
}
}
......
......@@ -15,14 +15,14 @@ int Counter;
int Color;
int LastIter, Depth, Ply, FollowPV, Totmat, Abort, NoAbort;
int DrawScore = -20;
int DrawScore = 0;
long AllDepth = 0;
int64 AllNPS = 0;
int64 Nodes;
/* params that cannot be pushed via SIGALM handler */
int A_n, A_i, A_d;
tmove * A_m;
volatile int A_n, A_i, A_d;
volatile tmove * A_m;
int N_moves[8] = { -21, -19, -12, -8, 21, 19, 12, 8 };
int RB_dirs[8] = { 1, -1, 10, -10, 11, -11, 9, -9 };
......@@ -80,24 +80,24 @@ int HS_[80] = /* hash codes for squares */
tdist dist[120*120];
inline int taxi_dist( int a, int b )
static inline int taxi_dist( int a, int b )
{ return abs( a%10 - b%10 ) + abs( a/10 - b/10 ); }
inline int diag_dist( int a, int b )
static inline int diag_dist( int a, int b )
{
int fdi = abs( a%10 - b%10 );
int rdi = abs( a/10 - b/10 );
return abs(rdi-fdi) + max(rdi,fdi);
}
inline int max_dist( int a, int b )
static inline int max_dist( int a, int b )
{
int fdi = abs( a%10 - b%10 );
int rdi = abs( a/10 - b/10 );
return max(rdi,fdi);
}
inline int min_dist( int a, int b )
static inline int min_dist( int a, int b )
{
int fdi = abs( a%10 - b%10 );
int rdi = abs( a/10 - b/10 );
......
/****************************
* easy levels
******************/
#include "phalanx.h"
void blunder( tmove *m, int *n )
{
int i;
int initp = Flag.easy * 4 + 150;
/* quick look (small Depth) makes blunders */
initp -= Depth/5;
/* full board means more blunders */
initp += (G[Counter].mtrl+G[Counter].xmtrl) / 200;
if(Counter>2)
for( i=(*n)-1; i>=1 && (*n)>4; i-- )
{
/* compute the probability this move is not seen */
int p = initp;
/* missing PV moves is unlikely */
if( m[i].from==PV[0][Ply].from && m[i].to==PV[0][Ply].to )
p -= 200;
if( m[i].from==PV[Ply-1][Ply].from && m[i].to==PV[Ply-1][Ply].to )
p -= 200;
/* target square far from the center is more difficult to spot */
p += 2*dist[120*E4+m[i].to].taxi + dist[120*E4+m[i].to].max +
+ 2*dist[120*D5+m[i].to].taxi + dist[120*D5+m[i].to].max
/* so is target square far from previous opponents move */
+ 2*dist[120*G[Counter-1].m.to+m[i].to].taxi;
if( m[i].in2 ) /* captures - we tend to see this */
{
/* the more valuable the captured piece,
* the more likely we see the move. */
p -= 20 + Values[ m[i].in2 >> 4 ] / 20;
/* capture of last moved piece is spotted
* + extra bonus for recapture */
if( m[i].to == G[Counter-1].m.to )
{
p -= 20 + Values[ m[i].in2 >> 4 ] / 30;
if( G[Counter-1].m.in2 ) p -= 40; /* recapture */
}
/* very short captures */
switch( dist[120*m[i].from+m[i].to].max )
{
case 0: case 1: p -= 250; break;
case 2: p -= 150; break;
case 3: p -= 50; break;
}
}
else /* noncaptures - prune or reduce with power table info */
{
int pp=0;
unsigned short pf = P[m[i].from], pt = P[m[i].to];
unsigned short xpm, xbnm, xrm, xqm; /* enemy power masks */
int mpv = Values[m[i].in1 >> 4]; /* moving piece value */
if( Color == WHITE )
{ xpm=BPM; xbnm=(BNM|BBM); xrm=BRM; xqm=BQM; }
else
{ xpm=WPM; xbnm=(WNM|WBM); xrm=WRM; xqm=WQM; }
/* leaving an attacked square - reduce probability of
* the move being skipped */
if( pf&xpm ) pp -= (5 + mpv - P_VALUE)/10;
if( pf&xbnm && mpv >= N_VALUE ) pp -= (5 + mpv - N_VALUE)/10;
if( pf&xrm && mpv >= R_VALUE ) pp -= (5 + mpv - R_VALUE)/10;
if( pf&(xqm|xrm|xbnm|xpm) ) pp -= mpv/100;
/* going to an attacked square - raise probability
* the move is skipped */
if( pt&xpm ) pp += (10 + mpv - P_VALUE)/10;
if( pt&xbnm && mpv >= N_VALUE ) pp += (10 + mpv - N_VALUE)/10;
if( pt&xrm && mpv >= R_VALUE ) pp += (10 + mpv - R_VALUE)/10;
if( pt&(xqm|xrm|xbnm|xpm) ) pp += mpv/50;
p += pp;
/* careless reductions to achieve depth at these low nps */
if( pp>=0 ) m[i].dch += 50 + min( 2*pp, 90 );
}
/* We focus on the piece that moved 2 plies ago and see the
* moves of the same piece */
if( m[i].from == G[Counter-2].m.to ) p -= 55;
/* underpromotions? too precise! */
if( m[i].in1 != m[i].in2a && piece(m[i].in2a) != QUEEN )
p += 15;
else
p -= 5;
/* dont see long moves, especially diagonal ones */
p += dist[120*m[i].from+m[i].to].taxi * 3;
/* dont see some knight moves */
if( piece(m[i].in1) == KNIGHT )
p += 10;
/* going backward? (white)Bf6xc3 is much more difficult
* to see than (white)Bc3xf6 ***/
if( Color==WHITE )
p += 4 * ( m[i].to/10 - m[i].from/10 );
else
p += 4 * ( m[i].from/10 - m[i].to/10 );
if( rand()%1000 < p )
{ m[i] = m[(*n)-1]; (*n)--; }
}
}
......@@ -51,7 +51,41 @@ return PWINS-8*steps;
/**
*** Some simple drawish knowledge - white cannot access critical square.
**/
if( wp<A7 && bk-wp==10 ) return PDRAWS;
if( dist[120*bk+wp+10].max == 1 && dist[120*wk+wp+10].max -wtm > 1 )
return PDRAWS;
if( wp<A7 ) /* pawn on row 2..6 */
{
if( bk-wp == 10 ) return PDRAWS;
if( wp>A6 && wp<H6 ) /* pawn on 6th row */
{
if( bk-wp == 20 )
{
if( wtm && ( wk-wp==1 || wk-wp==-1 ) )
return PWINS;
else return PDRAWS;
}
if( bk-wp==19 || bk-wp==21 )
{
if( !wtm && ( wk-wp==1 || wk-wp==-1 ) )
return PWINS;
else return PDRAWS;
}
}
}
else /* pawn is on 7th row already */
if( bk-wp == 10 )
{
if( wtm ) /* stronger side to move */
{ if( wp-wk == 10 ) return PWINS-8*steps; }
else
{ if( wp-wk == 9 || wp-wk==11 ) return PWINS; }
return PDRAWS; /* all other cases drawn */
}
if( wp<A6 )
{
if( bk-wp==20 ) return PDRAWS;
......@@ -320,7 +354,6 @@ if( G[Counter].mtrl && G[Counter].xmtrl )
}
else