SamChess by Jonathan Kreuzer must have one of the smallest sources.
http://www.3dkingdoms.com/chess/sam/samchess.html
Jim.
What is maximum rating per programmed line...
Moderator: Ras
-
Jim Ablett
- Posts: 2390
- Joined: Fri Jul 14, 2006 7:56 am
- Location: London, England
- Full name: Jim Ablett
-
ZirconiumX
- Posts: 1361
- Joined: Sun Jul 17, 2011 11:14 am
- Full name: Hannah Ravensloft
Re: What is maximum rating per programmed line...
It is non-portable.Jim Ablett wrote:SamChess by Jonathan Kreuzer must have one of the smallest sources.
http://www.3dkingdoms.com/chess/sam/samchess.html
Jim.
Code: Select all
matthew$ g++ -O3 -o sam *.cpp
movegen.cpp:38: error: '__int64' has not been declared
movegen.cpp:210: error: '__int64' does not name a type
movegen.cpp:211: error: expected ',' or '...' before 'HashKey'
movegen.cpp:211: error: ISO C++ forbids declaration of '__int64' with no type
movegen.cpp: In function 'int Repetition(int)':
movegen.cpp:212: error: 'nStart' was not declared in this scope
movegen.cpp:213: error: 'ahead' was not declared in this scope
movegen.cpp:214: error: 'ahead' was not declared in this scope
movegen.cpp:214: error: 'RepNum' was not declared in this scope
movegen.cpp:214: error: 'HashKey' was not declared in this scope
movegen.cpp: At global scope:
movegen.cpp:217: error: expected ',' or '...' before 'HashKey'
movegen.cpp:217: error: ISO C++ forbids declaration of '__int64' with no type
movegen.cpp: In function 'void AddRepBoard(int)':
movegen.cpp:217: error: 'RepNum' was not declared in this scope
movegen.cpp:217: error: 'ahead' was not declared in this scope
movegen.cpp:217: error: 'HashKey' was not declared in this scope
movegen.cpp: At global scope:
movegen.cpp:219: error: '__int64' does not name a type
movegen.cpp:260: error: '__int64' does not name a type
movegen.cpp:270: error: ISO C++ forbids declaration of 'AddRepBoard' with no type
movegen.cpp: In static member function 'static void TEntry::Create_HashFunction()':
movegen.cpp:254: error: 'HashFunction' was not declared in this scope
movegen.cpp:258: error: 'HashSTM' was not declared in this scope
movegen.cpp:258: error: 'HashFunction' was not declared in this scope
movegen.cpp: At global scope:
movegen.cpp:274: error: '__int64' does not name a type
movegen.cpp: In function 'int ABSearch(SBoard&, int, int, int, int, int&, int)':
movegen.cpp:283: error: '__int64' was not declared in this scope
movegen.cpp:283: error: expected `;' before 'n64Hash'
movegen.cpp:285: error: 'g_Nodes' was not declared in this scope
movegen.cpp:285: error: 'g_CheckNodes' was not declared in this scope
movegen.cpp:315: error: 'g_Nodes' was not declared in this scope
movegen.cpp:320: error: 'n64Hash' was not declared in this scope
movegen.cpp:320: error: 'HashBoard' is not a member of 'TEntry'
movegen.cpp:329: error: 'n64Hash' was not declared in this scope
movegen.cpp: In function 'void ComputerMove(SBoard&, int&, int&)':
movegen.cpp:346: error: 'g_Nodes' was not declared in this scope
movegen.cpp:347: error: 'g_CheckNodes' was not declared in this scope
winboard.cpp: At global scope:
winboard.cpp:45: error: '__int64' has not been declared
winboard.cpp: In function 'void SendThinking(int, int, int, int, int)':
winboard.cpp:48: error: invalid conversion from 'const char*' to 'char*'
winboard.cpp:48: error: initializing argument 1 of 'void GetMoveString(char*, char*, int)'
winboard.cpp: In function 'void WinboardLoop()':
winboard.cpp:82: error: 'HashBoard' is not a member of 'TEntry'
winboard.cpp:95: error: 'g_Nodes' was not declared in this scope
winboard.cpp:103: error: 'HashBoard' is not a member of 'TEntry'
winboard.cpp: In function 'void LogOutput(char*, char*)':
winboard.cpp:6: error: 'FILE' was not declared in this scope
winboard.cpp:6: error: 'fp' was not declared in this scope
winboard.cpp:6: error: 'fopen' was not declared in this scope
winboard.cpp:8: error: 'fprintf' was not declared in this scope
winboard.cpp:9: error: 'fclose' was not declared in this scope
winboard.cpp: At global scope:
winboard.cpp:13: error: variable or field 'LogBoard' declared void
winboard.cpp:13: error: 'SBoard' was not declared in this scope
winboard.cpp:13: error: 'Board' was not declared in this scope
winboard.cpp:14: error: expected ',' or ';' before '{' token
winboard.cpp:30: error: variable or field 'ReplayGame' declared void
winboard.cpp:30: error: 'SBoard' was not declared in this scope
winboard.cpp:30: error: 'Board' was not declared in this scope
winboard.cpp:30: error: expected primary-expression before 'int'
winboard.cpp:30: error: initializer expression list treated as compound expression
winboard.cpp:30: error: expected ',' or ';' before '{' token
winboard.cpp: In function 'void GetMoveString(char*, char*, int)':
winboard.cpp:35: error: 'SRC' was not declared in this scope
winboard.cpp:35: error: 'DST' was not declared in this scope
winboard.cpp:36: error: 'File' was not declared in this scope
winboard.cpp:36: error: 'Rank' was not declared in this scope
winboard.cpp:36: error: 'sprintf' was not declared in this scope
winboard.cpp: In function 'void SendMove(int)':
winboard.cpp:41: error: 'printf' was not declared in this scope
winboard.cpp:42: error: 'stdout' was not declared in this scope
winboard.cpp:42: error: 'fflush' was not declared in this scope
winboard.cpp: At global scope:
winboard.cpp:45: error: '__int64' has not been declared
winboard.cpp: In function 'void SendThinking(int, int, int, int, int)':
winboard.cpp:48: error: invalid conversion from 'const char*' to 'char*'
winboard.cpp:48: error: initializing argument 1 of 'void GetMoveString(char*, char*, int)'
winboard.cpp:49: error: 'clock' was not declared in this scope
winboard.cpp:49: error: 'g_start' was not declared in this scope
winboard.cpp:49: error: 'printf' was not declared in this scope
winboard.cpp:50: error: 'stdout' was not declared in this scope
winboard.cpp:50: error: 'fflush' was not declared in this scope
winboard.cpp: At global scope:
winboard.cpp:53: error: 'SBoard' has not been declared
winboard.cpp: In function 'int GetMove(char*, int&)':
winboard.cpp:57: error: 'SQ' was not declared in this scope
winboard.cpp: In function 'void WinboardLoop()':
winboard.cpp:66: error: 'SBoard' was not declared in this scope
winboard.cpp:66: error: expected `;' before 'Board'
winboard.cpp:67: error: 'BLACK' was not declared in this scope
winboard.cpp:71: error: 'FILE' was not declared in this scope
winboard.cpp:71: error: 'fp' was not declared in this scope
winboard.cpp:71: error: 'fopen' was not declared in this scope
winboard.cpp:72: error: 'fclose' was not declared in this scope
winboard.cpp:75: error: 'stdin' was not declared in this scope
winboard.cpp:75: error: 'fgets' was not declared in this scope
winboard.cpp:76: error: 'sscanf' was not declared in this scope
winboard.cpp:78: error: 'Board' was not declared in this scope
winboard.cpp:82: error: 'TEntry' has not been declared
winboard.cpp:82: error: 'HashBoard' was not declared in this scope
winboard.cpp:82: error: 'AddRepBoard' was not declared in this scope
winboard.cpp:83: error: 'LogBoard' cannot be used as a function
winboard.cpp:90: error: 'clock' was not declared in this scope
winboard.cpp:90: error: 'srand' was not declared in this scope
winboard.cpp:91: error: 'rand' was not declared in this scope
winboard.cpp:93: error: 'ComputerMove' was not declared in this scope
winboard.cpp:95: error: 'clock' was not declared in this scope
winboard.cpp:95: error: 'g_start' was not declared in this scope
winboard.cpp:95: error: 'g_Nodes' was not declared in this scope
winboard.cpp:96: error: 'fprintf' was not declared in this scope
winboard.cpp:97: error: 'fclose' was not declared in this scope
winboard.cpp:103: error: 'TEntry' has not been declared
winboard.cpp:103: error: 'HashBoard' was not declared in this scope
winboard.cpp:103: error: 'AddRepBoard' was not declared in this scope
winboard.cpp:104: error: 'LogBoard' cannot be used as a function
winboard.cpp:109: error: 'g_MaxTime' was not declared in this scope
winboard.cpp:109: error: 'CLOCKS_PER_SEC' was not declared in this scope
winboard.cpp:114: error: 'WHITE' was not declared in this scope
winboard.cpp:116: error: 'ReplayGame' cannot be used as a function
winboard.cpp:117: error: 'ReplayGame' cannot be used as a function
So I think Sam is out of the running, there Jim.
Matthew:out
tu ne cede malis, sed contra audentior ito
-
Uri Blass
- Posts: 11150
- Joined: Thu Mar 09, 2006 12:37 am
- Location: Tel-Aviv Israel
Re: What is maximum rating per programmed line...
It may be interesting also to optimize for smallest use of memoryPiotr Cichy wrote:TSCP is obviously not a program with short source code. For example, nanoSzachy 4.0 has about 1200 lines of code (38020 bytes) and pikoSzachy 4.0 about 800 lines (24247 bytes). And this is "clean" code, not "obfuscated" like in case of microMax (there are comments, long variable names etc). Both programs are optimized for size, but size of executable file and not size of source code. The size of exe files is: 30.5 KB (nano) and 9.5 KB (piko). And they are much stronger than TSCP or microMax:pocopito wrote:Well, I guess this is an "it depends" case.
Are you thinking of something like micro-max or toledo, that are written in a few more than 1000 _characters_? On the other hand if you're thinking about something written in a more readable way, I guess that TSCP itself has around 2600 lines of C code (I guess it implements alpha-beta + null move + qscent + move ordering, and many of the lines are coments), its strength isn't that bad and I guess there's a lot of possibilities to improve for example in the evaluation function.
Regards
E Diaz
CEGT 40/4:
CCRL 40/40:Code: Select all
NanoSzachy 4.0 x64 2381 PikoSzachy 4.0 2289 TSCP 1.81 1734
Code: Select all
NanoSzachy 4.0 64-bit 2563 Micro-Max 4.8 (DM-PII) 1699
that means playing strength relative to the memory that you need to run the program(that means that it is better if the program run with no hash
if you optimize to elo divided by size in bytes and not size of the code but size of the exe including the memory that the process is using).
-
lucasart
- Posts: 3243
- Joined: Mon May 31, 2010 1:29 pm
- Full name: lucasart
Re: What is maximum rating per programmed line...
That's quite impressive! Here's what I get with my engine DiscoCheckPiotr Cichy wrote: For example, nanoSzachy 4.0 has about 1200 lines of code (38020 bytes) and pikoSzachy 4.0 about 800 lines (24247 bytes). And this is "clean" code, not "obfuscated" like in case of microMax (there are comments, long variable names etc). Both programs are optimized for size, but size of executable file and not size of source code. The size of exe files is: 30.5 KB (nano) and 9.5 KB (piko). And they are much stronger than TSCP or microMax:
CEGT 40/4:
Code: Select all
NanoSzachy 4.0 x64 2381 PikoSzachy 4.0 2289 TSCP 1.81 1734
Code: Select all
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C 17 636 582 3146
C/C++ Header 17 120 304 439
-------------------------------------------------------------------------------
SUM: 34 756 886 3585
-------------------------------------------------------------------------------
It is 100% portable and not obfuscated (MicroMax style). I'll try to clean up my code a little and see if I can reduce it a little, while making it more readable at the same time (since comments don't count).
The size of the Linux x86-64 executable is 82.2 KB, which is a lot larger than NanoSzachy
-
JBNielsen
- Posts: 267
- Joined: Thu Jul 07, 2011 10:31 pm
- Location: Denmark
Re: What is maximum rating per programmed line...
Yes, very impressive.
Indeed it is quite impressive. I think we both follow the same philosophy of trying to keep the code short at a reasonable strength, but my program is both bigger and weaker than yours. It's a pity that they aren't open source.
Thanks for the information.
What is the best open source program regarding rating/size of source/readability?
-
JBNielsen
- Posts: 267
- Joined: Thu Jul 07, 2011 10:31 pm
- Location: Denmark
Re: What is maximum rating per programmed line...
You are right. Counting characters must be better.Lines of code don't make any sense, especially in C. Here's an example that should make it obvious:
But every variable should be (counted as) fx 10 char long.
-
hgm
- Posts: 28447
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: What is maximum rating per programmed line...
It depends how you define 'readability'.
I of course would say it is micro-Max. The slight inconvenience of having 1-character variable names is IMO more than compensated by the fact that every line is commented to say what it does. You catch on quickly enough as to what the variables mean, especially since there can be only 52.
And if the in-source comments are not enough, there is about 30 web pages of description on how it works...
I of course would say it is micro-Max. The slight inconvenience of having 1-character variable names is IMO more than compensated by the fact that every line is commented to say what it does. You catch on quickly enough as to what the variables mean, especially since there can be only 52.
And if the in-source comments are not enough, there is about 30 web pages of description on how it works...
-
Jim Ablett
- Posts: 2390
- Joined: Fri Jul 14, 2006 7:56 am
- Location: London, England
- Full name: Jim Ablett
Re: What is maximum rating per programmed line...
Only takes 10 mins to make it portable (add '-fpermissive' when compiling)Jim Ablett wrote:
SamChess by Jonathan Kreuzer must have one of the smallest sources.
http://www.3dkingdoms.com/chess/sam/samchess.html
Jim.
It is non-portable.
Code: Select all
// A small chess program by Jonathan Kreuzer
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include <stdint.h>
int GameMoves[ 1000 ];
const int HASH_SIZE = 400000;
const int INVALID=32, IV=32, EMPTY=0, WHITE=8, BLACK=16, WH=8, BL=16, PAWN=0, KNIG=1, BISH=2, ROOK=3, QUEE=4, KING=5;
const int TIME = 300000;
const int B_QS = 4, B_KS = 8, W_QS = 1, W_KS = 2;
const int N_dirs[8] = {-21, -19, -12, -8, 8, 12, 19, 21};
const int K_dirs[8] = {1, 9, 10, 11, -1, -9, -10, -11};
const int Q_dirs[8] = {1, -1, 9, -9, -10, 10, -11, 11};
const int R_dirs[4] = {1, -1, -10, 10};
const int B_dirs[4] = {9, -9, -11, 11};
const int P_dirs[8] = {-10, -20, -9, -11, 10, 20, 9, 11};
int inline SRC ( int Move ) {return (Move&127);}
int inline DST ( int Move ) {return ((Move>>7)&127);}
int inline PROMO ( int Move ) {return ((Move>>14)&3);}
int inline VALUE ( int Move ) {return ((Move>>16)&16383);}
int inline SWITCH ( int Color ){return Color^(WHITE|BLACK);}
int inline File ( int Sq ) {return (Sq-20)%10;}
int inline Rank ( int Sq ) {return (Sq-10)/10;}
int inline SQ ( int file, int rank) {return 21+file+rank*10;}
int EvalSq [ 26 * 128 ];
int SetCastle[120];
const unsigned char StartBoard[120] = { IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
IV, ROOK|BL, KNIG|BL, BISH|BL, QUEE|BL, KING|BL, BISH|BL, KNIG|BL, ROOK|BL, IV,
IV, PAWN|BL, PAWN|BL, PAWN|BL, PAWN|BL, PAWN|BL, PAWN|BL, PAWN|BL, PAWN|BL, IV,
IV, 0, 0, 0, 0, 0, 0, 0, 0, IV, IV, 0, 0, 0, 0, 0, 0, 0, 0, IV, IV, 0, 0, 0, 0, 0, 0, 0, 0, IV, IV, 0, 0, 0, 0, 0, 0, 0, 0, IV,
IV, PAWN|WH, PAWN|WH, PAWN|WH, PAWN|WH, PAWN|WH, PAWN|WH, PAWN|WH, PAWN|WH, IV,
IV, ROOK|WH, KNIG|WH, BISH|WH, QUEE|WH, KING|WH, BISH|WH, KNIG|WH, ROOK|WH, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV };
const int PieceValues[8] = { 100, 328, 330, 522, 952, 5000 };
const int MPieceValues[8] = { 00, 328, 330, 522, 952, 00 };
const int KingEval[10] = { 0, 8, 12, 5, 0, 0, 5, 14, 9, 0};
const int CentEval[10] = { 0,-6, -3, -1, 0, 0, -1, -3, -6, 0};
const int Cent[10] = { 0, 1, 2, 2, 3, 3, 2, 1, 1, 0};
void SendThinking ( int move, int Depth, int Eval, int64_t Nodes, int bFinished );
struct SBoard
{
unsigned char m_Sqs[120];
int stm, Eval, EPsq, Castling, WKsq, BKsq, WMat, BMat, nMoves, nLastCapOrPawn;
void Init() {
int sq, pc;
for (sq = 0; sq < 120; sq++) m_Sqs[sq] = StartBoard [ sq ];
Eval = 0; nMoves = 0;
Castling = 0;
stm = WHITE;
WKsq = 95; BKsq = 25;
BMat = WMat = 2*PieceValues[BISH]+2*PieceValues[KNIG]+2*PieceValues[ROOK]+PieceValues[QUEE];
for (sq = 0; sq < 120; sq++) SetCastle[sq] = 0;
SetCastle[21] = B_QS; SetCastle[28] = B_KS; SetCastle[25] = B_QS|B_KS; SetCastle[91] = W_QS; SetCastle[98] = W_KS; SetCastle[95] = W_QS|W_KS;
// Evaluation is incremental and uses the piece square table in EvalSq arrays.
for (pc = 0; pc < 8; pc++)
for (sq = 0; sq < 120; sq++) {
EvalSq[ ((pc|WHITE)<<7)+sq ] = PieceValues[pc];
EvalSq[ ((pc|BLACK)<<7)+sq ] = -PieceValues[pc];
if (pc == PAWN)
{EvalSq[ ((pc|WHITE)<<7)+sq ] += (9-Rank(sq)) * Cent[File(sq)];
EvalSq[ ((pc|BLACK)<<7)+sq ] -= Rank(sq) * Cent[File(sq)];}
else if (pc == KING) {}
else{if (pc!=ROOK && Rank(sq)==8) EvalSq[ ((pc|WHITE)<<7)+sq ] -= 8;
if (pc!=ROOK && Rank(sq)==1) EvalSq[ ((pc|BLACK)<<7)+sq ] += 8;
EvalSq[ ((pc|WHITE)<<7)+sq ] += CentEval[ File(sq) ];
EvalSq[ ((pc|BLACK)<<7)+sq ] -= CentEval[ File(sq) ];
}
EvalSq[ (0<<7)+sq ] = (Rank(sq)-9)*2 + KingEval[File(sq)]; // King Values depend on stage
EvalSq[ (1<<7)+sq ] = (Rank(sq))*2 - KingEval[File(sq)];
EvalSq[ (2<<7)+sq ] = 2*CentEval[ File(sq) ];
EvalSq[ (3<<7)+sq ] = -2*CentEval[ File(sq) ];
}
}
int CanCastleKS ( const int Color) {
if (Color == WHITE && !(Castling&W_KS) && m_Sqs[ WKsq+1 ] == EMPTY && !ColorAttacksSq(BLACK, WKsq+1) && m_Sqs[ WKsq+2 ] == EMPTY ) return 1;
if (Color == BLACK && !(Castling&B_KS) && m_Sqs[ BKsq+1 ] == EMPTY && !ColorAttacksSq(WHITE, BKsq+1) && m_Sqs[ BKsq+2 ] == EMPTY ) return 1;
return 0; }
int CanCastleQS ( const int Color) {
if (Color == WHITE && !(Castling&W_QS) && m_Sqs[ WKsq-1 ] == EMPTY && !ColorAttacksSq(BLACK, WKsq-1) && m_Sqs[ WKsq-2 ] == EMPTY && m_Sqs[ WKsq-3 ] == EMPTY) return 1;
if (Color == BLACK && !(Castling&B_QS) && m_Sqs[ BKsq-1 ] == EMPTY && !ColorAttacksSq(BLACK, BKsq-1) && m_Sqs[ BKsq-2 ] == EMPTY && m_Sqs[ BKsq-3 ] == EMPTY) return 1;
return 0; }
void AdjustMat ( int Dst, const int Mul ) {
if (m_Sqs[ Dst ]&WHITE) WMat += Mul*MPieceValues[ (m_Sqs[ Dst ]&7) ];
else BMat += Mul*MPieceValues[ (m_Sqs[ Dst ]&7) ];
}
void MovePiece (const int Src, const int Dst, const int Promo) {
int Piece = m_Sqs [Src];
Eval += EvalSq [ (Piece<<7) + Dst ] - EvalSq [ (Piece<<7) + Src ];
if (m_Sqs[ Dst ] != EMPTY)
{ Eval -= EvalSq [ (m_Sqs[ Dst ]<<7) + Dst ];
AdjustMat ( Dst, -1); }
m_Sqs[Dst] = Piece;
m_Sqs[Src] = EMPTY;
if (Piece == (KING|WH) ) WKsq = Dst;
if (Piece == (KING|BL) ) BKsq = Dst;
if ((Piece&7) == PAWN ) {
if (Dst < 30 || Dst > 90) {m_Sqs[Dst] += Promo + 1;
AdjustMat ( Dst, 1 );
Eval += EvalSq [ (m_Sqs[Dst]<<7) + Dst ] - EvalSq [ (Piece<<7) + Dst ]; }
if ( Dst == EPsq ) {EPsq = Src+File(Dst)-File(Src);
Eval -= EvalSq [ (m_Sqs[ EPsq ]<<7) + EPsq ];
m_Sqs [ EPsq ] = EMPTY;}
if ( abs(Src-Dst)==20) EPsq = ((Src + Dst)>>1); else EPsq = 0;
}
else EPsq = 0;
}
void DoMove ( const int Move ) {
int Dst = DST(Move), Src = SRC(Move);
Castling |= SetCastle[ Src ] | SetCastle[ Dst ];
nMoves++;
stm = SWITCH (stm);
if ((m_Sqs [Src]&7) == KING) {
if (Dst == Src-2) {MovePiece (Src, Src-2, 0); MovePiece (Src-4, Src-1, 0); return; }
if (Dst == Src+2) {MovePiece (Src, Src+2, 0); MovePiece (Src+3, Src+1, 0); return; } }
MovePiece (Src, Dst, PROMO(Move));
}
int CheckDirec ( int Sq, const int Dir, const int Piece1, const int Piece2) {
Sq += Dir;
while ( m_Sqs[ Sq ] == EMPTY ) Sq += Dir;
if ( m_Sqs[ Sq ] == Piece1 || m_Sqs[ Sq ] == Piece2) return 1; else return 0;
}
int ColorAttacksSq ( int Color, int Sq) {
int i;
for (i = 0; i < 8; i++) if (m_Sqs[Sq+N_dirs[i]] == (KNIG|Color)) return 1;
for (i = 0; i < 8; i++) if (m_Sqs[Sq+K_dirs[i]] == (KING|Color)) return 1;
for (i = 0; i < 4; i++) if (CheckDirec (Sq, R_dirs[i], (QUEE|Color), (ROOK|Color)) ) return 1;
for (i = 0; i < 4; i++) if (CheckDirec (Sq, B_dirs[i], (QUEE|Color), (BISH|Color)) ) return 1;
int n = (Color == WHITE) ? 4:0;
for (i = 2; i <= 3; i++) if (m_Sqs[Sq+P_dirs[i + n]] == (PAWN|Color)) return 1;
return 0;
}
int IsCheck (int color) {return (color == WHITE) ? ColorAttacksSq(BLACK, WKsq) : ColorAttacksSq(WHITE, BKsq);}
int Evaluate() {
if (WMat < 1400 && BMat < 1400) return Eval + EvalSq[ (2<<7)+WKsq ] + EvalSq[ (3<<7)+BKsq ];
return Eval + EvalSq[ (0<<7)+WKsq ] + EvalSq[ (1<<7)+BKsq ]; }
};
struct SMovelist
{
int m_Moves[256];
int m_nMoves, m_nAttacks, m_bCaps;
unsigned char *m_pSqs;
void inline AddMove (int Src, int Dst) { if (m_bCaps) return;
m_Moves[ m_nMoves++ ] = Src + (Dst<<7) + (3<<14) + (200<<16); }
void inline AddAtkMove (int Src, int Dst) { m_Moves[ m_nMoves++ ] = Src + (Dst<<7) + (3<<14) + ( (200+PieceValues[(m_pSqs[Dst]&7)]) << 16); }
void inline GenPieceMoves ( const int MoveArray[], const int bSlide, const int nDirs, int Sq, SBoard &Board, const int COLOR ) {
for (int i = 0; i < nDirs; i++) {
int tempSq = Sq + MoveArray[i];
if (bSlide)
while ( Board.m_Sqs [ tempSq ] == EMPTY ) {
AddMove (Sq, tempSq);
tempSq += MoveArray[i];
}
if ( Board.m_Sqs[tempSq]&SWITCH(COLOR) ) AddAtkMove ( Sq, tempSq );
else if (Board.m_Sqs[tempSq] == EMPTY ) AddMove (Sq, tempSq);
}
}
void inline GenPawnMoves ( const int MoveArray[], int Sq, SBoard &Board, const int COLOR ) {
int n = (COLOR == BLACK) ? 4:0;
if ( Board.m_Sqs[ Sq+P_dirs[n+0] ] == EMPTY ) {
if ( StartBoard[Sq]==(PAWN|SWITCH(COLOR))) AddAtkMove (Sq, Sq+P_dirs[n+0]); else AddMove (Sq, Sq+P_dirs[n+0]);
if ( StartBoard[Sq]==(PAWN|COLOR) && Board.m_Sqs[ Sq+P_dirs[n+1] ] == EMPTY) AddMove (Sq, Sq+P_dirs[n+1]);
}
if ( Sq+P_dirs[n+2] == Board.EPsq || (Board.m_Sqs[ Sq+P_dirs[n+2] ]&SWITCH(COLOR)) ) AddAtkMove (Sq, Sq+P_dirs[n+2]);
if ( Sq+P_dirs[n+3] == Board.EPsq || (Board.m_Sqs[ Sq+P_dirs[n+3] ]&SWITCH(COLOR)) ) AddAtkMove (Sq, Sq+P_dirs[n+3]);
}
void Generate ( SBoard &Board, int bCaps ) {
m_nMoves = 0;
m_bCaps = bCaps;
m_pSqs = Board.m_Sqs;
int Color = Board.stm;
for ( int Sq = 20; Sq < 100; Sq ++)
switch (Board.m_Sqs[ Sq ]^Color ) {
case PAWN: GenPawnMoves ( P_dirs, Sq, Board, Color ); break;
case KNIG: GenPieceMoves ( N_dirs, 0, 8, Sq, Board, Color ); break;
case BISH: GenPieceMoves ( B_dirs, 1, 4, Sq, Board, Color ); break;
case ROOK: GenPieceMoves ( R_dirs, 1, 4, Sq, Board, Color ); break;
case QUEE: GenPieceMoves ( Q_dirs, 1, 8, Sq, Board, Color ); break;
case KING: GenPieceMoves ( K_dirs, 0, 8, Sq, Board, Color );
if ( !Board.IsCheck (Color) ) {
if ( Board.CanCastleQS ( Color ) ) AddMove (Sq, Sq-2);
if ( Board.CanCastleKS ( Color ) ) AddMove (Sq, Sq+2);}
break;
};
}
void ScoreMoves ( SBoard &Board, const int Color, int BestMove ) {
for (int i = 0; i < m_nMoves; i++) {
int Dst = DST (m_Moves[i]), Src = SRC(m_Moves[i]);
int Piece = Board.m_Sqs[ Src ];
if (Color == WHITE) m_Moves[i] += ((EvalSq [ (Piece<<7) + Dst ] - EvalSq [ (Piece<<7) + Src ])<<16);
if (Color == BLACK) m_Moves[i] -= ((EvalSq [ (Piece<<7) + Dst ] - EvalSq [ (Piece<<7) + Src ])<<16);
if ( (m_Moves[i]&65535) == (BestMove&65535) ) m_Moves[i] += (2048<<16);
}
}
int GetNextMove ( int &nMove ) {
int Max = -1, Next = -1;
for (int i = 0; i < m_nMoves; i++)
if (m_Moves[i] && VALUE(m_Moves[i]) > Max) {
nMove = m_Moves[i];
Next = i;
Max = VALUE(nMove);}
if (Next == -1) return 0;
m_Moves[Next] = 0;
return 1;
}
};
int64_t RepNum[ 2000 ];
int inline Repetition ( const int64_t HashKey, int nStart, int ahead) {
int i = (nStart > 0) ? nStart : 0;
if ((i&1) != (ahead&1)) i++;
for ( ; i < ahead; i+=2) if (RepNum[i] == HashKey) return true;
return false;
}
void inline AddRepBoard ( const int64_t HashKey, int ahead ) {RepNum[ ahead ] = HashKey;}
uint64_t HashFunction [128][16], HashSTM;
struct TEntry
{
unsigned long m_checksum;
short m_eval, m_bestmove;
char m_depth, m_failtype, m_ahead, m_age;
void inline Read ( unsigned long CheckSum, short alpha, short beta, int &bestmove, int &value, int depth, int ahead) {
if (m_checksum == CheckSum ) {
if (m_depth >= depth) {
int tempVal = m_eval;
if (abs (m_eval) > 18000) {
if (m_eval > 0) tempVal = m_eval - ahead + m_ahead;
if (m_eval < 0) tempVal = m_eval + ahead - m_ahead;
}
switch ( m_failtype ) {
case 0: value = tempVal; break;
case 1: if (tempVal <= alpha) value = tempVal; break;
case 2: if (tempVal >= beta) value = tempVal; break;
}
}
if (depth > 2) bestmove = m_bestmove;
}
}
void inline Write ( unsigned long CheckSum, short alpha, short beta, int &bestmove, int &value, int depth, int ahead) {
m_checksum = CheckSum;
m_eval = value;
m_ahead = ahead;
m_depth = depth;
m_bestmove = (bestmove & 65535);
if (value <= alpha) m_failtype = 1; else if (value >= beta) m_failtype = 2; else m_failtype = 0;
}
static void Create_HashFunction () {
for (int i = 0; i <128; i++)
for (int x = 0; x < 16; x++) {
HashFunction [i][x] = rand() + (rand()*256) + (rand()*65536);
HashFunction [i][x] <<= 32;
HashFunction [i][x] += rand() + (rand()*256) + (rand()*65536);
}
HashSTM = HashFunction[0][0];
}
static uint64_t HashBoard (const SBoard &Board) {
uint64_t CheckSum = 0;
for (int index = 21; index <= 99; index++) {
int nPiece = Board.m_Sqs [ index ];
if (nPiece == INVALID) continue;
if (nPiece != EMPTY) CheckSum ^= HashFunction [ index ][ (nPiece&15) ];
}
if (Board.stm == BLACK) CheckSum ^= HashSTM;
return CheckSum;
}
//static AddRepBoard ( );
};
TEntry TTable[ HASH_SIZE ];
int64_t g_Nodes, g_CheckNodes;
int g_MaxTime;
clock_t g_start;
int ABSearch ( SBoard &InBoard, int alpha, int beta, int depth, int ahead, int &BestMove, int bNull )
{
SMovelist Moves;
SBoard Board;
int Color = InBoard.stm, Eval, NextBest = 0, nMove, bInCheck = InBoard.IsCheck (Color);
int64_t n64Hash;
if ( g_Nodes > g_CheckNodes ) {
g_CheckNodes = g_Nodes+10000;
if ((clock()-g_start) > g_MaxTime) return TIME;
}
if ( (!bInCheck && depth <= 0) || depth < 0 || ahead > 32 ) {
int Eval = (InBoard.stm == WHITE) ? InBoard.Evaluate() : -InBoard.Evaluate();
if (Eval > alpha) alpha = Eval;
if (alpha >= beta) return beta;
Moves.Generate ( InBoard, 1 );
}
else {
if (bNull && depth > 2 && !bInCheck
&& ((Color==WHITE && InBoard.WMat > 400) || (Color==BLACK && InBoard.BMat > 400))) {
InBoard.stm = SWITCH (InBoard.stm);
Eval = -ABSearch ( InBoard, -beta, -beta+1, depth-3, ahead, NextBest, false);
InBoard.stm = SWITCH (InBoard.stm);
if (Eval == -TIME) return TIME;
if (Eval >= beta) return beta;
}
Moves.Generate ( InBoard, 0 );
}
if (BestMove < 100 && depth > 2) {Eval = ABSearch ( InBoard, alpha, beta, depth-2, ahead+1, BestMove, true);
if (Eval == TIME) return TIME;}
Moves.ScoreMoves ( InBoard, Color, BestMove );
BestMove = 0;
while ( Moves.GetNextMove ( nMove ) ) {
Board = InBoard;
Board.DoMove ( nMove );
g_Nodes++;
if ( Board.IsCheck ( Color ) ) continue;
NextBest = 0; Eval = -32000;
if (depth > 1) {
n64Hash = TEntry::HashBoard ( Board );
if (Repetition ( n64Hash, Board.nMoves - 40, Board.nMoves)) Eval = 0;
else {AddRepBoard ( n64Hash, Board.nMoves);
TTable [ ((unsigned long)n64Hash) % HASH_SIZE ].Read ( (unsigned long)(n64Hash>>32), alpha, beta, NextBest, Eval, depth-1, ahead);
}
}
if (Eval == -32000)
{Eval = -ABSearch (Board, -beta, -alpha, (bInCheck)?(depth):(depth-1), ahead+1, NextBest, true );
if (Eval == -TIME) return TIME;}
if (depth > 1) TTable [ ((unsigned long)n64Hash) % HASH_SIZE ].Write ( (unsigned long)(n64Hash>>32), alpha, beta, NextBest, Eval, depth-1, ahead);
if ( Eval > alpha) {
if (ahead == 0) SendThinking ( nMove, depth, Eval, g_Nodes, false);
BestMove = nMove;
alpha = Eval;
if (alpha >= beta) return beta;
}
if (BestMove == 0) BestMove = 1;
}
if ( !Moves.m_bCaps && BestMove == 0) {return (bInCheck) ? -20000+ahead : 0;}
return alpha;
}
void ComputerMove( SBoard &Board, int &Move, int &Eval )
{
g_Nodes = 0;
g_CheckNodes = g_Nodes+10000;
g_start = clock();
int SearchEval, SearchMove;
for (int nDepth = 2; nDepth < 16; nDepth++) {
SearchEval = ABSearch (Board, -30000, 20001-nDepth, nDepth, 0, SearchMove, false);
if (SearchEval != TIME) Eval = SearchEval;
if (SearchMove > 100) { Move = SearchMove;
SendThinking ( Move ,nDepth, Eval, g_Nodes, true);}
if ((clock()-g_start) > (g_MaxTime/2)) break;
if (abs(Eval)>= (20001-nDepth)) break;
}
}
void LogOutput ( char *pre, char *s )
{
FILE *fp = fopen ("outlog.txt", "at");
if (fp) {
fprintf (fp, "%s%s\n", pre, s );
fclose (fp);
}
}
void LogBoard ( SBoard &Board )
{
const char cPieces[16] = { 'p', 'n', 'b', 'r', 'q', 'k', 0, 0, 'P', 'N', 'B', 'R', 'Q', 'K',0, 0};
char s[1024];
int j = 0;
strcpy (s, "");
for (int i = 20; i < 100; i++) {
if ( (i%10) == 0 || (i%10)==9) continue;
if (Board.m_Sqs[i] == 0) j+=sprintf (s+j, " . ");
if ((Board.m_Sqs[i]&BLACK)) j+=sprintf (s+j, " %c ", cPieces[(Board.m_Sqs[i]&7)]);
if ((Board.m_Sqs[i]&WHITE)) j+=sprintf (s+j, " %c ", cPieces[(Board.m_Sqs[i]&7)+8]);
if ( (i%10) == 8) j+=sprintf (s+j, "\n");
}
j+=sprintf (s+j, "%d, %d : PCSq: %d\n", Board.WMat, Board.BMat, Board.Evaluate());
LogOutput ("", s);
}
void ReplayGame ( SBoard &Board, int nMoves ) {
Board.Init();
for( int i = 0; i < nMoves; i++) Board.DoMove ( GameMoves [i] );
}
void GetMoveString ( char *preFix, char *sMove, int move) {
int Src = SRC(move), Dst = DST(move);
sprintf (sMove, "%s%c%c%c%c\n", preFix, File(Src)+'a'-1, 9-Rank(Src)+'0', File(Dst)+'a'-1, 9-Rank(Dst)+'0' );
}
void SendMove ( int move) {
char sMove[128];
GetMoveString ( "move ",sMove, move );
printf ( "%s", sMove );
fflush (stdout);
LogOutput ("sent> ", sMove);
}
void SendThinking ( int move, int Depth, int Eval, int64_t Nodes, int bFinished )
{
char sMove[128];
GetMoveString ( (char *)((bFinished)?"":"*"), sMove, move );
printf("%d %d %d %I64d %s\n", Depth, Eval, (clock()-g_start)/10, Nodes, sMove);
fflush (stdout);
}
int GetMove ( char *s, SBoard &Board )
{
if (s[0] < 'a' || s[0] > 'h' || s[1] < '0' || s[1] > '9' || s[2] < 'a' || s[2] > 'h' || s[3] < '0' || s[3] > '9') return -1;
LogOutput ("GotMove> ", s);
int Src = SQ(s[0]-'a',7-(s[1]-'1')), Dst = SQ(s[2]-'a', 7-(s[3]-'1') ), Upgrade = 3;
if (s[4]=='n' || s[4]=='N') Upgrade = 0;
if (s[4]=='b' || s[4]=='B') Upgrade = 1;
if (s[4]=='r' || s[4]=='R') Upgrade = 2;
return Src + (Dst<<7) + (Upgrade<<14);
}
void WinboardLoop ( )
{
SBoard Board;
char CompColor = BLACK;
char line[1024], cmd[1024];
int move = 1, Eval = 0, time, inc = 0;
FILE *fp = fopen ("outlog.txt", "wt");
if (fp) fclose (fp);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
fflush(NULL);
signal(SIGINT, SIG_IGN);
while ( 1==1 ) {
if (!fgets(line, 1000, stdin)) return;
sscanf (line, "%s", cmd);
LogOutput ("> ", line);
if (strcmp (cmd, "protover") == 0) {
printf("feature myname=\"SamChess\"\n");
printf("feature variants=\"normal\"\n");
printf("feature sigint=0\n");
printf("feature sigterm=0\n");
printf("feature analyze=0\n");
printf("feature colors=1\n");
printf("feature done=1\n");
continue;
}
move = GetMove ( line, Board );
if (move > 1) {
GameMoves [ Board.nMoves ] = move;
Board.DoMove (move);
AddRepBoard ( TEntry::HashBoard ( Board ), Board.nMoves);
LogBoard ( Board );
}
if (strcmp (cmd, "go") == 0) CompColor = Board.stm;
if (strcmp (cmd, "force") == 0) CompColor = -1;
if (CompColor == Board.stm) {
move = 0;
if (Board.nMoves == 0) {srand ( clock() );
if (rand()%100 > 40) move = (85)+(65<<7); else move = (84)+(64<<7);
}
else ComputerMove ( Board, move, Eval );
FILE *fp = fopen ("outlog.txt", "at");
if (fp) {int nps = ((clock()-g_start)==0) ? 0: (int)((g_Nodes*1000)/(clock()-g_start));
fprintf (fp, "Eval: %d Nodes %I64d Time %d NPS %d\n", Eval, g_Nodes, clock()-g_start, nps );
fclose (fp);
}
if (move) {
SendMove ( move);
GameMoves [ Board.nMoves ] = move;
Board.DoMove ( move );
AddRepBoard ( TEntry::HashBoard ( Board ), Board.nMoves);
LogBoard ( Board );
}
}
if (strcmp (cmd, "time") == 0) {
sscanf(line, "time %d", &time);
g_MaxTime = (CLOCKS_PER_SEC/100) * (time/30) + (inc * CLOCKS_PER_SEC);
}
if (strcmp (cmd, "level") == 0) {sscanf(line, "level %d %d %d", &time, &time, &inc); }
if (strcmp (cmd, "new") == 0) {Board.Init(); CompColor = BLACK;}
if (strcmp (cmd, "quit") == 0) return;
if (strcmp (cmd, "white") == 0) CompColor = WHITE;
if (strcmp (cmd, "black") == 0) CompColor = BLACK;
if (strcmp (cmd, "undo") == 0) ReplayGame ( Board, Board.nMoves - 1);
if (strcmp (cmd, "remove") == 0) ReplayGame ( Board, Board.nMoves - 2);
}
}
int main ( ) {
TEntry::Create_HashFunction ( );
WinboardLoop ( );
return 1;
}
-
JBNielsen
- Posts: 267
- Joined: Thu Jul 07, 2011 10:31 pm
- Location: Denmark
Re: What is maximum rating per programmed line...
Would be very interesting!lucasart wrote: Here's what I get with my engine DiscoCheckAbout 2600 elo on CEGT 40/20. Last version tested was 3.6.2 (2575 elo), and version 3.7.1 is about 30 elo better in self testing.Code: Select all
------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- C 17 636 582 3146 C/C++ Header 17 120 304 439 ------------------------------------------------------------------------------- SUM: 34 756 886 3585 -------------------------------------------------------------------------------
It is 100% portable and not obfuscated (MicroMax style). I'll try to clean up my code a little and see if I can reduce it a little, while making it more readable at the same time (since comments don't count).
The size of the Linux x86-64 executable is 82.2 KB, which is a lot larger than NanoSzachy
-
JBNielsen
- Posts: 267
- Joined: Thu Jul 07, 2011 10:31 pm
- Location: Denmark
Re: What is maximum rating per programmed line...
You have a very good point here!hgm wrote:It depends how you define 'readability'.
I of course would say it is micro-Max. The slight inconvenience of having 1-character variable names is IMO more than compensated by the fact that every line is commented to say what it does. You catch on quickly enough as to what the variables mean, especially since there can be only 52.
And if the in-source comments are not enough, there is about 30 web pages of description on how it works...