- A bug in the new 'game over' check for winboard that made the engine crash was fixed
- The transposition tables now use depth/new replacement scheme
mediocre_v0.231b
1: Mediocre v0.23b uci 64,5/100So Mediocre has gotten a bit stronger.
2: Mediocre v0.22b uci 35,5/100
mainClassName=MediocreYou need to have paths set to the Java bin-directory on your system for this to work (try typing 'java' in a console window, if you do not get an error you have it set).
classPath=bin
app.arg0=u
1: Kingsout 120,5/140The only real conclusions we can draw from this is King's Out clearly being the strongest and Tscp second, the 3-5 places are too close to call.
2: Tscp181 84,5/140
3: Mediocre v0.23b dev 54,0/140
4: Roce350 47,5/140
5: Mediocre v0.22b 43,5/140
3: Mediocre v0.23b dev 20,5/35 101101111101===0=1001001=10101=011=Quite close but the check extension seems to give a slight edge.
5: Mediocre v0.22b 14,5/35 010010000010===1=0110110=01010=100=
2rq1rk1/p5bp/bp2pnp1/n1ppNp2/2PP4/PP1BPN2/1B3PPP/2RQ1RK1 b - - 3 14
Ply Eval Time Nodes LineAs you can see it takes quite some time to get to 7 plies depth. But the node count is only 152535. That kind of node count takes about a second in most positions, and not 53 seconds like here.
1 -15 140 36 Bb7
2 -25 219 179 Bb7 Qc2
3 -15 875 678 Bb7 Qc2 Nc6
4 -15 1156 2040 Bb7 Qc2 Nc6 Rb1
5 -10 4906 9434 Bb7 Qc2 Nc6 cxd5 exd5
6 -15 11359 29397 Bb7 Qc2 Nc6 Nxc6 Bxc6 Ne5
7 -10 53578 152535 Bb7 cxd5 Qxd5 b4 Qa2 Qe2 Nb3
Ply Eval Time Nodes LineExactly the same evaluation and line, and time used is about the same (this differs some from search to search of course). But the node count is fifty times as high.
1 -15 140 7484 Bb7
2 -25 218 19992 Bb7 Qc2
3 -15 687 97129 Bb7 Qc2 Nc6
4 -15 953 140802 Bb7 Qc2 Nc6 Rb1
5 -10 4234 674731 Bb7 Qc2 Nc6 cxd5 exd5
6 -15 10390 1675138 Bb7 Qc2 Nc6 Nxc6 Bxc6 Ne5
7 -10 50812 8200247 Bb7 cxd5 Qxd5 b4 Qa2 Qe2 Nb3
Engine Score v.22 v.23 v.21 v.2 v.12The v0.23b dev is the development version, it has some adaptive null move pruning and check extensions but it is not working like it should yet.
1: Mediocre v0.22b 13,5/16 ···· 1101 11== 1=11 1111
2: Mediocre v0.23b dev 11,0/16 0010 ···· 01== 1111 1111
3: Mediocre v0.21b 7,0/16 00== 10== ···· 1110 1000
4: Mediocre v0.2b 5,5/16 0=00 0000 0001 ···· 1111
5: Mediocre v0.12b 3,0/16 0000 0000 0111 0000 ····
rating win loss draw total bestTime control for pretty much all games was 2 minutes without increment. Among the beaten opponents were two FMs (fide master) and a WIM (woman international master).
Bullet 2051 146 19 22 187 2085
Ply Eval Time Nodes LineMediocre v0.22b
1 20 109 21 Nc3
2 0 140 107 Nc3 Nc6
3 20 156 223 Nc3 Nc6 Nf3
4 0 203 728 Nc3 Nc6 Nf3 Nf6
5 7 281 2066 Nc3 Nc6 Nf3 Nf6 d4
6 0 625 5940 Nc3 Nc6 Nf3 Nf6 d4 d5
7 15 1922 25719 Nc3 Nc6 Nf3 Nf6 d4 d5 Be3
8 0 7015 81963 Nc3 Nc6 Nf3 Nf6 d4 d5 Be3 Be6
9 19 136609 1085895 e4 Nf6 e5 Nd5 Nf3 Nc6 Bc4 Nb6 Na3
Total time: 2:16.609
Ply Eval Time Nodes LineThe new version is almost 2 minutes faster to 9 ply. A remarkable difference really.
1 20 47 21 Nc3
2 0 79 107 Nc3 Nc6
3 20 79 223 Nc3 Nc6 Nf3
4 0 94 728 Nc3 Nc6 Nf3 Nf6
5 7 125 2066 Nc3 Nc6 Nf3 Nf6 d4
6 0 172 5940 Nc3 Nc6 Nf3 Nf6 d4 d5
7 15 329 25406 Nc3 Nc6 Nf3 Nf6 d4 d5 Be3
8 0 938 79321 Nc3 Nc6 Nf3 Nf6 d4 d5 Be3 Be6
9 19 19235 1176165 e4 Nf6 e5 Nd5 Nf3 Nc6 Bc4 Nb6 Na3
Total time: 19.250
long zobrist -> 64 bitsAnd if we have an entry at each slot:
int depth -> 32 bits
int flag -> 32 bits
int eval -> 32 bits
int ancient -> 32 bits
Move move
int pieceMoving -> 32 bits
int fromIndex -> 32 bits
int toIndex -> 32 bits
int capture -> 32 bits
int moveType -> 32 bits
int[] prevpos
int en passant -> 32 bits
int wcastling -> 32 bits
int bcastling -> 32 bits
int halfmoves -> 32 bits
Total -> 480 bits
Slots (2^20) -> 1048576So at full load the transposition table with 2^20 slots (like Mediocre has) would take 60mb of memory.
2^20 * 480 -> 503316480 bits
Total -> 60 mb
long zobrist -> 64 bitsAnd if we have an entry at each slot:
int move -> 32 bits
int depth/flag/eval/ancient -> 32 bits
Total -> 128 bits
Slots (2^20) -> 1048576Now we only use 16mb for the same table that took 64mb before. If we go up one 'size' to 2^21 slots we use 32mb and 2^22 uses 64mb.
2^20 * 128 -> 134217728 bits
Total -> 16 mb
public int[] history;In the makeMove()-method:
public int historyIndex;
history[historyIndex] = 0;And in the unmakeMove()-method:
if(enPassant != -1)
{
history[historyIndex] =
enPassant;
}
history[historyIndex] = history[historyIndex] |
(white_castle << 7)
| (black_castle << 9)
| (movesFifty << 16);
historyIndex++;
historyIndex--;Notice how my constant for 'no' enPassant (-1) is giving me trouble again. We can not store -1 in the integer since it would result in a weird value. I really have to do something about this soon.
if(((history[historyIndex]) & 127) == 0)
{
enPassant = -1;
}
else
{
enPassant = ((history[historyIndex]) & 127);
}
white_castle = ((history[historyIndex] >> 7) & 3);
black_castle = ((history[historyIndex] >> 9) & 3);
movesFifty = ((history[historyIndex] >> 16) & 127);
if(pieceOnSquare <= 0) continue;cut another 10-20% off the generation time.
Depth Nodes Time
1 20 0.000
2 400 0.000
3 8902 0.047
4 197281 0.312
5 4865609 7.750
6 119060324 3:23.094
Depth Nodes TimeIt is about 10% faster than the old routine, but still almost a full ply slower compared to other engines. I do not know what I might be doing wrong. I have removed all slow 'new' commands, that is replaced pretty much every object creation there was. Also I switched all Vector objects to arrays, and even stopped creating a local array with moves for every ply and instead used one larger array used for all depths (with limited benefits).
1 20 0.000
2 400 0.000
3 8902 0.047
4 197281 0.422
5 4865609 10.219
6 119060324 4:24.047
int toShift = 7;We 'shift' the values to the right position and then use 'or' which changes the right bits to 1 instead of 0. It could look like this:
int pieceShift = 14;
int captureShift = 18;
int typeShift = 22;
int move = -1;
move =
(from)
| (to << toShift)
| (piece << pieceShift)
| (capture << captureShift)
| (type << typeShift);
54 = 110110 (in binary from)And we have a long row of zeros we want to add it to.
...0000000000000000000000000Now we shift the 54 to the right position. That is we add seven zeros behind it like this:
1101100000000And now we 'or' it to the row of zeros:
...0000000000000000000000000If we want to add type=5 (101). Shift it to the right position (i.e. add 22 zeros behind it):
OR ...0000000000001101100000000
= ...0000000000001101100000000
1010000000000000000000000And then 'or' it to the integer:
...0000000000001101100000000So now we have the type in the right position and so on for all the other values. The 'from'-position is in the beginning so we do not need to shift it.
OR ...1010000000000000000000000
= ...1010000000001101100000000
int squareMask = 127;First we shift the piece of the code we want to the beginning. Then we apply a 'mask' and 'and' with it, it could look like this like this to retrieve the to-value:
int pieceMask = 15;
int typeMask = 7;
from = (move & squareMask);
to = ((move >> toShift) & squareMask);
piece =((move >> pieceShift) & pieceMask);
capture = ((move >> captureShift) & pieceMask));
type = ((move >> typeShift) & pieceMask));
...10010110110001101011001011We now have the to-value.
Shift:
...00000001001011011000110101 (the to-values are now first)
And with the mask:
...00000001001011011000110101
AND ...00000000000000000001111111
= ...00000000000000000000110101