N.E.G. 0.3 was actually a slightly modified version of my regular alpha-beta engine Joker, which was closed source. I haven't worked on that since 2008, and I am not even sure I do have sources, as this is many computers ago.
The Ram 2.0 source is below. It should be linked with the MersenneTwister random generator.
Code: Select all
#include <stdio.h>
#ifdef WIN32
# include <windows.h>
#else
# include <sys/time.h>
# include <sys/times.h>
# include <unistd.h>
int GetTickCount()
{ struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec*1000 + t.tv_usec/1000;
}
#endif
#define WHITE 8
#define BLACK 16
#define COLOR (WHITE|BLACK)
double genrand64_real2(void);
int MTinit(int t);
unsigned int MyRandom(unsigned int n)
{
unsigned int res = n*genrand64_real2();
return res;
}
typedef void Func(int stm, int from, int to, void *closure);
typedef int Board[128];
int value[8] = { 0, 100, 100, 10000, 325, 350, 500, 950 };
int firstDir[] = { 0, 0, 27, 4, 18, 8, 13, 4 };
int steps[] = { -16, -15, -17, 0, 1, -1, 16, -16, 15, -15, 17, -17, 0, 1, -1, 16, -16, 0, 18, 31, 33, 14, -18, -31, -33, -14, 0, 16, 15, 17, 0 };
Board PST = {
0, 2, 4, 6, 6, 4, 2, 0, 0,0,0,0,0,0,0,0,
2, 8,10,12,12,10, 8, 2, 0,0,0,0,0,0,0,0,
6,12,16,18,18,16,12, 6, 0,0,0,0,0,0,0,0,
8,14,18,20,20,18,14, 8, 0,0,0,0,0,0,0,0,
8,14,18,20,20,18,14, 8, 0,0,0,0,0,0,0,0,
6,12,16,18,18,16,12, 6, 0,0,0,0,0,0,0,0,
2, 8,10,12,12,10, 8, 2, 0,0,0,0,0,0,0,0,
0, 2, 4, 6, 6, 4, 2, 0, 0,0,0,0,0,0,0,0
};
// "abcdefghijklmnopqrstuvwxyz"
char pieces[] = ".5........3..4.176........";
int pVal[] = { 0, 1, 1, 10, 3, 3, 5, 9 };
Board board, checkRay;
int Zobrist[8*128], posKey, cnt50;
int bestScore, bestFrom, bestTo, lastMover, lastChecker, randomize, post, king, seq, minors, alwaysQueen, biased, silent;
unsigned int nMoves[2], moveList[2][4096], keyHash[2][1024];
#define C1 40
#define C2 40
#define P1 250
#define P2 250
#define N1 75
#define N2 75
#define M1 60
#define M2 60
#define K1 50
#define K2 50
#define Q1 30
#define Q2 30
int strategy[2][8][8] = {
{ { 0, 0, 0, 0, 0, 0, 0, 35 },
{ 1,400,400, P1, P1, P1, P1,400 },
{ 1,400,400, P1, P1, P1, P1,400 },
{ 1, K1, K1, K1, K1, K1, K1, K1 },
{ 1, N1, N1, N1,150, N1, N1, N1 },
{ 1, M1, M1, M1, M1,100, M1,100 },
{ 1, C1, C1, C1, C1, C1, 60,100 },
{ 1, 6, 6, Q1, 25, 80, 80,100 },
},
{ { 0, 0, 0, 0, 0, 0, 0, 35 },
{ 1,400,400, P2, P2, P2, P2,400 },
{ 1,400,400, P2, P2, P2, P2,400 },
{ 1, K2, K2, K2, K2, K2, K2, K2 },
{ 1, N2, N2, N2,150, N2, N2, N2 },
{ 1, M2, M2, M2, M2,100, M2,100 },
{ 1, C2, C2, C2, C2, C2, 60,100 },
{ 1, 6, 6, Q2, 25, 80, 80,100 },
},
};
int
MoveGen (int stm, int lastTo)
{
int move, from, to, piece, victim, type, dir, step, stop, vert, side = stm >> 4, n = 0;
king = -1; seq++;
for(from=0; from<128; from = from + 9 & ~8) {
piece = board[from];
if(piece) minors += 2 - ((piece & 6) == 4);
if(piece & stm) {
type = piece & 7;
dir = firstDir[type];
while((step = steps[dir++])) {
to = from;
do {
to += step;
if(to & 0x88) break;
stop = victim = board[to];
if((victim ^ piece) < WHITE) break; // captures friend
if(type < 3) { // Pawn
int vert = !(to - from & 7);
if(vert != !victim) break; // wrong mode
move = 256*from + to;
if(vert && (type == 1 ? to > 79 : to < 48)) stop--; // precompensate leaper on 3rd rank
if(type == 1 ? to < 16 : to > 111) { // promotion
move += (6 - side) << 16; // to Queen
move += strategy[side][0][7]<<20;
if(!alwaysQueen, 0)
moveList[side][n++] = move - (1<<16), // to Rook
moveList[side][n++] = move - (2<<16), // to Bishop
moveList[side][n++] = move - (3<<16); // to Knight
}
} else move = 256*from + to;
move += strategy[side][type][victim&7]<<20;
if((victim & 7) == 3) { // king capture
king = to;
if(lastTo != to)
do {
checkRay[to -= step] = seq; // mark check ray and attacker
} while(to != from);
return 1;
}
moveList[side][n++] = move;
stop += type < 5;
} while(!stop);
}
}
}
nMoves[side] = n;
return 0;
}
int draw50, rep3, stalemate, insuf, checkmate[3];
void
GameEnd (int result, char *msg)
{
if(result) checkmate[result+1]++; else
if(*msg == '3') rep3++; else
if(*msg == '5') draw50++; else
if(*msg == 'i') insuf++; else
if(*msg == 's') stalemate++;
if(silent) return;
printf("%s {%s}\n", result ? (result == 1 ? "1-0" : "0-1") : "1/2-1/2", msg);
fflush(stdout);
}
int
Pick (int side)
{
int n = nMoves[side];
if(!biased) return MyRandom(n);
int i, w;
for(i=w=0; i<n; i++) w += moveList[side][i] >> 20;
int x = MyRandom(w);
for(i=w=0; i<n; i++) {
w += moveList[side][i] >> 20;
if(w > x) return i;
}
return 0; // dead code
}
int
DrawCheck(int stm, int from, int to, int piece, int victim)
{
int side = stm >> 4;
posKey += Zobrist[128*(piece&7) + to + stm - WHITE]
- Zobrist[128*(piece&7) + from + stm - WHITE]
- Zobrist[128*(victim&7) + to - stm + BLACK];
int index = posKey & 1023;
int key = keyHash[side][index];
if((posKey ^ key) & ~1023) keyHash[side][index] = posKey & ~1023; // no match; save position key
else { // posKey was already hashed: repetition
if(keyHash[side][index]++ & 1) { GameEnd(0, "3-fold repetition"); return 1; }
}
if(cnt50 >= 100) { GameEnd(0, "50-move rule"); return 1; }
cnt50++; if(victim || (piece & 7) < 3) cnt50 = 0;
if(minors < 6) { GameEnd(0, "insufficient material"); return 1; }
return 0;
}
int
Think (int stm)
{
int from, to, piece, promo, pinSeq, pinned = -1, side = stm >> 4;
while(nMoves[side]) {
int n = Pick(side);
int move = moveList[side][n];
to = move & 0xFF; from = move >> 8 & 0xFF, promo = move >> 16 & 0xF; // decode
if(from == pinned && checkRay[to] != pinSeq) { // this moves a piece known to be pinned from the pin ray
moveList[side][n] = moveList[side][--nMoves[side]]; // delete the illegal move
continue; // and try again
}
int piece = board[from];
int victim = board[to]; board[to] = piece + promo; board[from] = 0; // make move
minors = 0; // set up to detect mating potential
if(!MoveGen(stm ^ COLOR, to)) {
static char *name[] = { "", "", "k", "n", "b", "r", "q" };
if(!silent) printf("move %c%d%c%d%s\n", (from&7)+'a', 8-(from>>4), (to&7)+'a', 8-(to>>4), name[promo+side]);
if(DrawCheck(stm, from, to, piece, victim)) return 1;
return 0;
}
board[from] = piece; board[to] = victim; // unmake move, as it was illegal
if((piece & 7) == 3) { // King stumbled into check
moveList[side][n] = moveList[side][--nMoves[side]]; // delete the illegal move and try again
} else if(checkRay[from] == seq) { // we moved a pinned piece
pinned = from; pinSeq = seq; // remember the pinned piece
moveList[side][n] = moveList[side][--nMoves[side]]; // delete the illegal move and try again
} else { // we must have been in check all along
int i, j, n = nMoves[side];
for(i=j=0; i<n; i++) { // examine all moves, to delete those that cannot solve this check
move = moveList[side][i];
if((move >> 8 & 0xFF) == king // King move
|| checkRay[move & 0xFF] == seq) // interposition or capture of checker
moveList[side][j++] = move; // keep it
}
nMoves[side] = j; // try again with the cleaned-up move list
}
}
// none of the moves is legal!
if(MoveGen(stm ^ COLOR, -1)) { // we are in check
GameEnd(stm == WHITE ? -1 : 1, "checkmate");
} else GameEnd(0, "stalemate");
return 1; // flag game end
}
int
Setup (char *fen)
{
char c;
int i;
for(i=0; i<128; i++) board[i] = 0;
i = 0;
while((c = *fen++)) {
if(c == 'p') board[i++] = BLACK + 2; else
if(c >= '0' && c <= '9') i += c - '0'; else
if(c >= 'a' && c <= 'z') board[i++] = BLACK + pieces[c - 'a'] - '0'; else
if(c >= 'A' && c <= 'Z') board[i++] = WHITE + pieces[c - 'A'] - '0'; else
if(c == '/') i = (i | 15) + 1; else break;
}
// for(i=0; i<128; i = i + 9 & ~8) printf(i&7 ? " %2d" : "\n# %2d", board[i]); printf("\n");
c = (*fen == 'w' ? WHITE : BLACK);
MoveGen(c, -1);
return c;
}
int
InitGame (char *fen)
{
int i;
if(!fen) fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
for(i=0; i<1024; i++) keyHash[0][i] = keyHash[1][i] = 0;
posKey = -1; cnt50 = 0;
return Setup(fen);
}
char *fens[] = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1",
NULL,
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
};
void RunMatch()
{
int i, f, t = GetTickCount();
silent = 1; // suppress all CECP output
for(i=f=0; i<1000000; i++) {
int stm;
if(!fens[f]) f = 0;
stm = InitGame(fens[f++]);
MoveGen(stm, -1);
while(!Think(stm)) { // play a game
stm ^= COLOR;
}
if(i%1000 == 999) printf("%7d: %8.2f sec, %5d %5d %5d %5d %5d %6d %8d\n", i+1, (GetTickCount() - t)/1000.,
checkmate[2], checkmate[0], stalemate, rep3, draw50, insuf, seq), fflush(stdout);
}
exit(0);
}
int
main ()
{
int i, stm = WHITE, engineSide = 0;
char line[256], command[20];
MTinit(GetTickCount()); for(i=0; i<50; i++) MyRandom(1);
for(i=128; i<128*8; i++) Zobrist[i] = MyRandom(-1);
while(1) {
int i, c;
if(stm == engineSide) {
if(Think(stm)) engineSide = 0;
stm ^= COLOR;
}
fflush(stdout); i = 0;
while((line[i++] = c = getchar()) != '\n') if(c == EOF) printf("# EOF\n"), exit(1); line[i] = '\0';
if(*line == '\n') continue;
sscanf(line, "%s", command);
printf("# command: %s\n", command);
if(!strcmp(command, "usermove")) {
int from, to; char c, d, promo, ep;
sscanf(line, "usermove %c%d%c%d%c", &c, &from, &d, &to, &promo);
from = (8 - from)*16 + c - 'a'; to = (8 - to)*16 + d - 'a';
int piece = board[from], victim = board[to];
if((piece & 7) == 3 && to - from == 2) board[from + 1] = board[to + 1], board[to + 1] = 0; // K-side castling
if((piece & 7) == 3 && from - to == 2) board[from - 1] = board[to - 2], board[to - 2] = 0; // Q-side castling
ep = ((piece & 7) < 3 && !victim); // recognize e.p. capture
board[to] = piece; if(ep) board[from & 0x70 | to & 7] = 0, victim = piece ^COLOR; board[from] = 0;
if(promo >= 'a') {
board[to] = board[to] | 7; // promote to Q
if(promo == 'n') board[to] -= 3; // correct for under-promotion
if(promo == 'b') board[to] -= 2;
if(promo == 'r') board[to] -= 1;
}
stm ^= COLOR;
MoveGen(stm, to);
if(DrawCheck(stm ^ COLOR, from, to, piece, victim)) engineSide = 0;
}
else if(!strcmp(command, "match")) RunMatch(); // not used as XBoard engine!
else if(!strcmp(command, "protover")) printf("feature option=\"always queen -check 0\n"),
printf("feature option=\"biased to capture -check 0\n"),
printf("feature myname=\"Ram 2.0\" setboard=1 usermove=1 analyze=0 colors=0 sigint=0 sigterm=0 done=1\n");
else if(!strcmp(command, "option")) sscanf(line+7, "always queen=%d\n", &alwaysQueen),
sscanf(line+7, "biased to capture=%d\n", &biased);
else if(!strcmp(command, "new")) stm = InitGame(NULL), randomize = 0, engineSide = BLACK;
else if(!strcmp(command, "go")) engineSide = stm;
else if(!strcmp(command, "result")) engineSide = 0;
else if(!strcmp(command, "force")) engineSide = 0;
else if(!strcmp(command, "setboard")) stm = Setup(line+9);
else if(!strcmp(command, "random")) randomize = !randomize;
else if(!strcmp(command, "post")) post = 1;
else if(!strcmp(command, "nopost")) post = 0;
else if(!strcmp(command, "quit")) break;
}
return 0;
}