How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Discussion of chess software programming and technical issues.

Moderator: Ras

shahil4242
Posts: 30
Joined: Thu Sep 28, 2017 5:20 pm

How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by shahil4242 »

This is my current code of my ui34p chess engine

Code: Select all

#include <stdio.h>
#define START_POSITION "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
#define ROW(i) (((i)  >> 4))
#define COL(i) (((i) & 7 ))

int color[128], piece[128], side, castle, ep, fifty;
int steps[43] = {
	 17,  15,   0,
	-33,  33, -31,  31, -18,  18, -14,  14,  0,
	-17,  17, -15,  15,   0,
	-16,  16,  -1,   1,   0,
	-17,  17, -16,  16, -15,  15,  -1,   1,  0,
	  0,   0,   1,   1,   1,   0,// piece + 31 -> slide
	  0,   3,  12,  17,  22,  22 // piece + 37 -> offset
};

void set_position(char *fen);
void print_position(void);
void movegen(void);

int search(int alpha,int beta,int depth) {
	return 0;
}

int main() {
	set_position("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -");
	print_position();
	movegen();
	printf("\n");
	return 0;
}

void set_position(char *fen) {
	int row = 7, col = 0, sq = 0;
	char sym[26] = ".2........5..1.043........";	
	for(sq = 0; sq <= 127; sq++) color[sq] = piece[sq] = 16;
	side = castle = ep = fifty = -1;
	while(!isspace(*fen)) {
		sq = row * 16 + col;
		if(*fen >= 'A' && *fen <= 'Z') {
			color[sq] = 0; piece[sq] = (sym[*fen - 'A'] - '0'); col = col + 1;
		} else if(*fen >= 'a' && *fen <= 'z') {
			color[sq] = 1; piece[sq] = (sym[*fen - 'a'] - '0'); col = col + 1;
		} else if(*fen >= '1' && *fen <= '8') {
			col = col + (*fen - '0');
		} else if(*fen == '/') {
			row = row - 1; col = 0;
		}
		fen++;
	}
	do {fen++;} while(isspace(*fen));
	switch(tolower(*fen)) { case 'w': side = 0; break; case 'b': side = 1; break; }	
	do {fen++;} while(isspace(*fen));
	castle = 0;
	while(*fen != '\0' && !isspace(*fen)) {
		if(*fen == 'K') castle |= 1; if(*fen == 'Q') castle |= 2;
		if(*fen == 'k') castle |= 4; if(*fen == 'q') castle |= 8;
		fen++;
	}	
	while(isspace(*fen)) fen++;
	ep = -1; fifty = 0;
	if(*fen != '\0' && *fen != '-') ep = (fen[1] - '1') * 16 + (fen[0] - 'a');
}

void print_position(void) {
	int row, col, sq;
	char piece_char[2][6] = {{'P','N','B','R','Q','K'},{'p','n','b','r','q','k'}};
	printf("\nBoard:\n\n");
	for(row = 7; row >= 0; row--) {
		for(col = 0; col <= 7; col++) {
			if(!col) printf("%c ",(row + '1'));
			sq = row * 16 + col;
			printf("%c%c ",
				(color[sq] == 1 ? '-' : ' '),
				((color[sq] & 16) ? '.' : piece_char[color[sq]][piece[sq]]));
		}
		printf("\n");
	}
	printf("   a  b  c  d  e  f  g  h\n\n");
	printf("   side   : %3c\n",(!(side)  ? 'w' : 'b'));
	printf("  xside   : %3c\n",(!(side ^ 1) ? 'w' : 'b'));
	printf("   castle : %3d\n",castle);
	printf("   ep     : %3d\n",ep);
	printf("   fifty  : %3d\n",fifty);
}

void movegen(void) {
	int sq, from, to, index, step, sign;
	for(sq = 0;sq <= 63; sq++) {
		from = sq + (sq & ~7);
		if(color[from] == side) {
			index = steps[37 + piece[from]];
			if(!piece[from]) {
				while(steps[index]) {
					to = from + (((!side) ? 1 : -1) * steps[index]);
					if(!(to & 0x88) && color[to] == (side ^ 1)) {
						printf("%d %3d %3d cap\n",piece[from],from,to);
					}
					index++;
				}
			} else {
				while(steps[index]) {
					for(to = from + steps[index];!(to & 0x88);to += steps[index]) {
						if(color[to] == side) break;
						if(color[to] == (side ^ 1)) {
							printf("%d %3d %3d cap\n",piece[from],from,to);
							break;
						}
						printf("%d %3d %3d norm\n",piece[from],from,to);
						if(!steps[31 + piece[from]]) break;
					}
					index++;
				}
			}
		}
	}
}
Note: there will be some debug function which i will remove later on
1. Is there any way to write minimal movegen()?
2. Is is_attacked () function is required? How castling is possible without is_attacked()?
3. What is the virgin bit in micromax?
I have seen micromax source code but i could understand at all

This is another experimental chess engine dy14g which is perft is working nicely How to implement minimal search with pv line.

Code: Select all

#include <stdio.h>
#include <sys/timeb.h>
#define START_POSITION "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
#define NAME    "dy14g"
#define VERSION "0.2.0"
#define AUTHOR  "Md Shahil Ahmed"

#define S(x,y) ((((x) * 8) + (y)))
#define R(x) (((x) / 8))
#define C(x) (((x) % 8))

#define M(x) ((x) + ((x) & ~7))
#define U(x) (((x) + ((x) & 7)) >> 1)

#define FROM(x) (((x) >> 6) & 63)
#define TO(x) ((x) & 63)
#define P(x) (((x) >> 12) & 7)
#define CAP(x) (((x) >> 15) & 7)
#define PROM(x) (((x) >> 18) & 7)

int color[64], piece[64], king[2], side, castle, ep, fifty;
char piece_char[2][6] = {{'P','N','B','R','Q','K'},{'p','n','b','r','q','k'}};
typedef struct {
	int move;
	int castle;
	int ep;
	int fifty;
} type_hist;
int dirs[34] = {
	 17,  15, 0, // 0 1 2
	-17, -15, 0, // 3 4 5
	 33,  31,  14, -18, -33, -31, -14,  18, 0, // 6 7 8 9 10 11 12 13 14
	 17,  15, -17, -15,   0, // 15 16 17 18 19
	 16,  -1, -16,   1,   0, // 20 21 22 23 24
	 17,  15, -17, -15,  16,  -1, -16,   1,  0 // 25 26 27 28 29 30 31 32 33	 
};
int slide[6] = { 0, 0, 1, 1, 1, 0};
int idx_pawn[2]  = {  0, 3};
int idx_piece[6] = { -1, 6, 15, 20, 25, 25};
int pawn_push[2] = {  8,-8};
int pawn_row_ep[2]    = { 3, 4};
int pawn_row_promo[2] = { 7, 0};

int ply, hply;
int moves[16381];
int counter[512];
type_hist hist[1024];


int get_ms() {
	struct timeb timebuffer;
	ftime(&timebuffer);
	return (timebuffer.time * 1000) + timebuffer.millitm;
}
char *sqstr(int sq) {
	static char str_sq[2];
	sprintf(str_sq,"xx");
	if(!(M(sq) & 0x88)) sprintf(str_sq,"%c%c",(char)(C(sq) + 'a'),(char)(R(sq) + '1'));
	str_sq[2] = 0;
	return str_sq;
}

int strsq(char *str_sq) {
	int sq = -1;
	if(str_sq[0] >= 'a' && str_sq[0] <= 'h' && str_sq[1] >= '1' && str_sq[1] <= '8')
		sq = S((int)(str_sq[1] - '1'),(int)((str_sq[0] - 'a')));
	return sq;
}

char *movestr(int move) {
	static char str_move[5];
	int prom = PROM(move);
	if(prom >= 1 && prom <= 4) {
		sprintf(str_move,"%c%c%c%c%c",
			C(FROM(move)) + 'a',R(FROM(move)) + '1',
			C(TO(move)) + 'a',R(TO(move)) + '1',piece_char[1][prom]);
		str_move[5] = 0;
	} else {
		sprintf(str_move,"%c%c%c%c",
			C(FROM(move)) + 'a',R(FROM(move)) + '1',
			C(TO(move)) + 'a',R(TO(move)) + '1');	
		str_move[4] = 0;
	}
	return str_move;
}

void set_position(char *fen) {
	int r = 7, c = 0, sq = 0;
	//             "abcdefghijklmnopqrstuvwxyz"
	char sym[26] = ".2........5..1.043........";
	
	for(sq = 0; sq < 128; sq++) color[sq] = piece[sq] = 6;	
	
	king[0] = king[1] = side = castle = ep = fifty = -1;
	memset(counter,0,sizeof(counter));
	ply = hply = counter[0] = 0;
	
	while(!isspace(*fen)) {
		sq = ((r * 8) + c);
		if(*fen >= 'A' && *fen <= 'Z') {
			color[sq] = 0; piece[sq] = (sym[*fen - 'A'] - '0');
			if(*fen == 'K') king[0] = sq;
			c = c + 1;
		} else if(*fen >= 'a' && *fen <= 'z') {
			color[sq] = 1; piece[sq] = (sym[*fen - 'a'] - '0');
			if(*fen == 'k') king[1] = sq;
			c = c + 1;
		} else if(*fen >= '1' && *fen <= '8') {
			c = c + (*fen - '0');
		} else if(*fen == '/') {
			r = r - 1; c = 0;
		}
		fen++;
	}
	do { fen++; } while(isspace(*fen));
	switch(tolower(*fen)) {
		case 'w': side = 0; break;
		case 'b': side = 1; break;
	}
	do { fen++; } while(isspace(*fen));
	castle = 0;
	while(*fen != '\0' && !isspace(*fen)) {
		switch(*fen) {
			case 'K': castle |= 1; break; case 'Q': castle |= 2; break;
			case 'k': castle |= 4; break; case 'q': castle |= 8; break;
		}
		fen++;
	}
	while(isspace(*fen)) { fen++; }
	ep = -1; fifty = 0;
	if(*fen != '\0' && *fen != '-') ep = strsq(fen);
}

int isattacked(int sq,int s) {
	int p, idx, to;
	for(p = 0; p <= 5; p++) {
		idx = idx_piece[p];
		if(!p) idx = idx_pawn[(s ^ 1)];
		while(dirs[idx]) {
			to = sq;
			while(1) {
				to = M(to) + dirs[idx]; if(to & 0x88) break; to = U(to);
				if(color[to] != 6) {
					if(color[to] == s && piece[to] == p) return 1;
					break;
				}
				if(!slide[p]) break;
			}
			idx = idx + 1;
		}
	}
	return 0;
}

int incheck(int s) {
	return isattacked(king[s],(s ^ 1));
}

void movegen() {
	int c, p, idx, from, to, tmp, move;
	counter[ply + 1] = counter[ply];
	for(from = 0; from <= 63; from++) {
		c = color[from], p = piece[from];
		if(c == side) {
			if(!p) {
				for(idx = 0; idx <= 1; idx++) {
					to = M(from) + dirs[idx_pawn[side] + idx];
					if(!(to & 0x88)) {
						to = U(to);
						if(color[to] == (side ^ 1)) {
							if(pawn_row_promo[side] == R(to)) {
								move = ((4 << 18) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
								moves[counter[ply + 1]] = move; counter[ply + 1] += 1;					
								move = ((3 << 18) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
								moves[counter[ply + 1]] = move; counter[ply + 1] += 1;					
								move = ((2 << 18) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
								moves[counter[ply + 1]] = move; counter[ply + 1] += 1;		
								move = ((1 << 18) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
								moves[counter[ply + 1]] = move; counter[ply + 1] += 1;		
							} else {
								move= ((piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
								moves[counter[ply + 1]] = move; counter[ply + 1] += 1;					
							}	
						}
						if(color[to] == 6 && ep != -1 && pawn_row_ep[(side ^ 1)] == R(from)) {
							if(ep == to && color[to] == color[to + pawn_push[side]]) {
								move= ((1 << 22) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
								moves[counter[ply + 1]] = move; counter[ply + 1] += 1;					
							}
						}
					}
				}
				to = from + pawn_push[side];
				if(color[to] == 6) {
					if(pawn_row_promo[side] == R(to)) {
						move = ((4 << 18) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;					
						move = ((3 << 18) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;					
						move = ((2 << 18) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;		
						move = ((1 << 18) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;		
					} else {
						move = ((piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;					
					}	
					to = from + 2 * pawn_push[side];
					if(pawn_row_ep[side] == R(to) && color[to] == 6) {
						move = ((1 << 21) | (piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;
					}
				}
			} else {
				idx = idx_piece[p];
				while(dirs[idx]) {
					to = from;
					while(1) {
						to = M(to) + dirs[idx];
						if(to & 0x88) break; to = U(to);
						if(color[to] == side) break;
						if(color[to] == (side ^ 1)) {
							move = ((piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
							moves[counter[ply + 1]] = move; counter[ply + 1] += 1;
							break;
						}
						move= ((piece[to] << 15) | (piece[from] << 12)| (from << 6) | to);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;
						if(!slide[p]) break;
					}
					idx = idx + 1;
				}			
			}
		}
	}
	if(!incheck(side)) {
		if(side) {
			if(castle & 4) {
				if(color[61] == 6 && color[62] == 6) {
					if(!isattacked(61,(side ^ 1)) && !isattacked(62,(side ^ 1))) {
						move = ((1 << 23) | (piece[62] << 15) | (piece[60] << 12)| (60 << 6) | 62);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;			
					}
				}
			}		
			if(castle & 8) {
				if(color[59] == 6 && color[58] == 6 && color[57] == 6) {
					if(!isattacked(59,(side ^ 1)) && !isattacked(58,(side ^ 1))) {
						move = ((1 << 23) | (piece[58] << 15) | (piece[60] << 12)| (60 << 6) | 58);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;			
					}
				}
			}		
		} else {
			if(castle & 1) {
				if(color[5] == 6 && color[6] == 6) {
					if(!isattacked(5,(side ^ 1)) && !isattacked(6,(side ^ 1))) {
						move = ((1 << 23) | (piece[6] << 15) | (piece[4] << 12)| (4 << 6) | 6);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;			
					}
				}
			}
			if(castle & 2) {
				if(color[3] == 6 && color[2] == 6 && color[1] == 6) {
					if(!isattacked(3,(side ^ 1)) && !isattacked(2,(side ^ 1))) {
						move = ((1 << 23) | (piece[2] << 15) | (piece[4] << 12)| (4 << 6) | 2);
						moves[counter[ply + 1]] = move; counter[ply + 1] += 1;			
					}
				}
			}
		}
	}
}

void unmake_move() {
	if(hply <= 0) return;
	
	ply = ply - 1; hply = hply - 1; side = (side ^ 1);
	
	int move = hist[hply].move;
	castle   = hist[hply].castle;
	ep       = hist[hply].ep;
	fifty    = hist[hply].fifty;
	
	int from = FROM(move), to = TO(move), cap = CAP(move), prom = PROM(move), p = P(move);
	
	
	color[to] = piece[to] = 6;
	if(cap != 6) {
		color[to] = (side ^ 1); piece[to] = cap;
	}
	color[from] = side;
	piece[from] = p;
	
	if(move & (1 << 22)) {
		color[to - pawn_push[side]] = (side ^ 1); piece[to - pawn_push[side]] = 0; 
	}
	
	if(p == 5) {
		king[side] = from;
		if(move & (1 << 23)) {
			switch(to) {
				case  6: color[5] = piece[5] = 6; color[7] = 0; piece[7] = 3; break;
				case  2: color[3] = piece[3] = 6; color[0] = 0; piece[0] = 3; break;
				case 62: color[61] = piece[61] = 6; color[63] = 1; piece[63] = 3; break;
				case 58: color[59] = piece[59] = 6; color[56] = 1; piece[56] = 3; break;
			}
		}
	}
	
}

int make_move(int move) {
	int from = FROM(move), to = TO(move), cap = CAP(move), prom = PROM(move), p = P(move);
	
	hist[hply].move   = move;
	hist[hply].castle = castle;
	hist[hply].ep     = ep;
	hist[hply].fifty  = fifty;
	
	switch (from)
	{
		case  7: castle &= (~1); break;
		case  4: castle &= (~(1|2)); break;
		case  0: castle &= (~2); break;
		case 63: castle &= (~4); break;
		case 60: castle &= (~(4|8)); break;
		case 56: castle &= (~8); break;
	}
	switch (to)
	{
		case  7: castle &= (~1); break;
		case  4: castle &= (~(1|2)); break;
		case  0: castle &= (~2); break;
		case 63: castle &= (~4); break;
		case 60: castle &= (~(4|8)); break;
		case 56: castle &= (~8); break;
	}
	
	fifty = fifty + 1;
	ep = -1;
	
	if(!p || cap != 6) fifty = 0;
	
	color[to] = side; piece[to] = p;
	color[from] = piece[from] = 6;
	
	if(move & (1 << 21)) { ep = to - pawn_push[side]; }
	
	if(move & (1 << 22)) { fifty = 0; color[to - pawn_push[side]] = piece[to - pawn_push[side]] = 6; }
	
	if(prom >= 1 && prom <= 4) { color[to] = side; piece[to] = prom; }
	
	if(p == 5) {
		king[side] = to;
		if(move & (1 << 23)) {
			switch(to) {
				case  6: color[7] = piece[7] = 6; color[5] = 0; piece[5] = 3; break;
				case  2: color[0] = piece[0] = 6; color[3] = 0; piece[3] = 3; break;
				case 62: color[63] = piece[63] = 6; color[61] = 1; piece[61] = 3; break;
				case 58: color[56] = piece[56] = 6; color[59] = 1; piece[59] = 3; break;
			}
		}
	}
	ply = ply + 1; hply = hply + 1; side = (side ^ 1);
	if(incheck(side ^ 1)) {
		unmake_move();
		return 0;
	}
	return 1;
}

void print_position(void) {
	int r, c, sq;
	printf("\nBoard\n\n");
	printf("     a    b    c    d    e    f    g    h");
	printf("\n  +----+----+----+----+----+----+----+----+\n");	
	for(r = 7; r >= 0; r--) {
		for(c = 0; c <= 7; c++) {
			if(!c) printf("%c",(r + '1'));
			sq = S(r,c);
			printf(" | %c%c",
				(color[sq] == 1 ? '-' : ' '),
				(color[sq] == 6 ? ' ' : piece_char[color[sq]][piece[sq]]));
		}
		printf(" | %c",(r + '1'));
		printf("\n  +----+----+----+----+----+----+----+----+\n");
	}
	printf("     a    b    c    d    e    f    g    h\n\n");
	printf("    king[white] : %3d %s\n",king[0],sqstr(king[0]));
	printf("    king[black] : %3d %s\n",king[1],sqstr(king[1]));	
	printf("    side  : %c in_check : %s\n",
		(side ? 'b' : 'w'),(incheck(side) ? "True" : "False"));
	printf("    xside : %c in_check : %s\n",
		((side ^ 1) ? 'b' : 'w'),(incheck(side ^ 1) ? "True" : "False"));
	printf("    castle : %3d %c%c%c%c\n",castle,
		((castle & 1) ? 'K' : '-'),((castle & 2) ? 'Q' : '-'),
		((castle & 4) ? 'k' : '-'),((castle & 8) ? 'q' : '-'));
	printf("    ep     : %3d %4s\n",ep,sqstr(ep));
	printf("    fifty  : %3d\n",fifty);
	printf("    ply    : %3d\n",ply);
	printf("    hply   : %3d\n",hply);
	printf("\n");
}

unsigned long long perft(int depth) {
	int i;
	unsigned long long nodes = 0;	
	if(depth == 0) return 1;
	movegen();
	for(i = counter[ply]; i < counter[ply + 1]; i++) {
		if(!make_move(moves[i])) continue;
		nodes = nodes + perft(depth-1);
		unmake_move();
	}
	return nodes;	
}

void test(void) {
	set_position(START_POSITION);
	print_position();
	//run_perft_test_data(4);
}

int main_loop(void) {
	printf("%s %s by %s (Copyright 2021)\n\n",NAME,VERSION,AUTHOR);
	test();
	return 0;
}

int main(void) {
	printf("\n");	
	main_loop();
	printf("\n");	
	return 0;
}
User avatar
xr_a_y
Posts: 1872
Joined: Sat Nov 25, 2017 2:28 pm
Location: France

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by xr_a_y »

I would recommand starting around this base engine : https://github.com/kz04px/4ku/tree/strength-1
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by hgm »

There is a somewhat better readable version of an old version of microMax at http://home.hccnet.nl/h.g.muller/maximax.txt . (It uses meaningful variable names.) This might be easier to understand.

The virgin bit keeps track of whether a piece has moved; it gets always set (through a |= 32 operation) on the piece in the to-square when a move is made. The move generator tests this bit to decide whether is should allow a double-push on pawns, or castling on a king.
shahil4242
Posts: 30
Joined: Thu Sep 28, 2017 5:20 pm

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by shahil4242 »

xr_a_y wrote: Wed Nov 17, 2021 8:29 am I would recommand starting around this base engine : https://github.com/kz04px/4ku/tree/strength-1
Thank you the resource is great.I had made a bitboard engine which is 80 times slower than my normal 0x88 chess engine.
shahil4242
Posts: 30
Joined: Thu Sep 28, 2017 5:20 pm

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by shahil4242 »

hgm wrote: Wed Nov 17, 2021 11:56 am There is a somewhat better readable version of an old version of microMax at http://home.hccnet.nl/h.g.muller/maximax.txt . (It uses meaningful variable names.) This might be easier to understand.

The virgin bit keeps track of whether a piece has moved; it gets always set (through a |= 32 operation) on the piece in the to-square when a move is made. The move generator tests this bit to decide whether is should allow a double-push on pawns, or castling on a king.
Now i could somewhat understand the source code.

For example there is castling move e1g1 but g1 square is attacked by black rook from g8.Without is_attacked(int sq,int side) How this is possible?
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by hgm »

MicroMax treats illegal castlings in the child node as e.p. capture of the king. Both on a pawn double push and a castling the square moved through is passed to the child as e.p. square. In the child, it is tested whether the to-square of a capture-capable move hits an e.p. square on the last rank, or the square left or right of it. If it does, the move leading to the node must have been an illegal castling (out of check, in check or through check), and we score the move as +INF (guaranteed to cause a beta cutoff). This will cause the move to be ignored in the parent (where it scored -INF).
shahil4242
Posts: 30
Joined: Thu Sep 28, 2017 5:20 pm

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by shahil4242 »

Thank you very much now i got it.
abulmo2
Posts: 467
Joined: Fri Dec 16, 2016 11:04 am
Location: France
Full name: Richard Delorme

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by abulmo2 »

You may have a look at dumb, it is about 1200 lines of code and 2677 Elo at CCRL 40/4.
You can also give a look at OliThink which is very strong (2867 Elo for version 5.9.7 on CCRL 40/4) with a very compact source code (1033 lines of code for version 5.10.1).
Richard Delorme
OliverBr
Posts: 797
Joined: Tue Dec 18, 2007 9:38 pm
Location: Munich, Germany
Full name: Dr. Oliver Brausch

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by OliverBr »

abulmo2 wrote: Wed Nov 17, 2021 2:01 pm You may have a look at dumb, it is about 1200 lines of code and 2677 Elo at CCRL 40/4.
You can also give a look at OliThink which is very strong (2867 Elo for version 5.9.7 on CCRL 40/4) with a very compact source code (1033 lines of code for version 5.10.1).
Actually dumb is really intriguing. It's very compact and well written.
Chess Engine OliThink: http://brausch.org/home/chess
OliThink GitHub:https://github.com/olithink
shahil4242
Posts: 30
Joined: Thu Sep 28, 2017 5:20 pm

Re: How to write 2200+ elo chess engine within 500 to 1000 lines of code with pure evaluation(No NNUE or EGTB)?

Post by shahil4242 »

OliverBr wrote: Thu Nov 18, 2021 11:40 pm
abulmo2 wrote: Wed Nov 17, 2021 2:01 pm You may have a look at dumb, it is about 1200 lines of code and 2677 Elo at CCRL 40/4.
You can also give a look at OliThink which is very strong (2867 Elo for version 5.9.7 on CCRL 40/4) with a very compact source code (1033 lines of code for version 5.10.1).
Actually dumb is really intriguing. It's very compact and well written.
I think one of the version of OliThink had uses rotated bitboard.What is the result of perft? Does it is faster than magic bitboard?is it is woth learning about rotated bitboard.