Today I've made an experiment:
1. Extracted material/PST/game phase material margin values from https://hxim.github.io/Stockfish-Evaluation-Guide/
2. Removed scaling and everything apart the pure tapered evaluation
3. Played 100 games versus https://www.chessprogramming.org/Simpli ... n_Function at 0s+100ms timecontrol (depth 5-6)
Here're the results where 1.1 is simplified eval and 1.3a is stockfish simplified eval:
Code: Select all
-----------------WukongJS 1.1-----------------
WukongJS 1.1 - WukongJS 1.3a : 56,5/100 45-32-23 (===00111000=11101001100=1=11011=00=01001001110=1111101=0=111=0=00=11111100=1=00=01111=011=1=11=001==) 57% +49
-----------------WukongJS 1.3a-----------------
WukongJS 1.3a - WukongJS 1.1 : 43,5/100 32-45-23 (===11000111=00010110011=0=00100=11=10110110001=0000010=1=000=1=11=00000011=0=11=10000=100=0=00=110==) 44% -42
while lost games are mostly forced mate occurred due to unfortunate openings.
Here's the PGN:
https://github.com/maksimKorzh/wukongJS ... lified.pgn
Here's SF's material + PST + tapered eval implementation in javascript (since my engine is written in JS):
Code: Select all
/****************************\
============================
EVALUATION
============================
\****************************/
/*
Following material weights and PST values are taken from
https://hxim.github.io/Stockfish-Evaluation-Guide/
*/
// material score
const materialWeights = [
// opening material score
[0, 124, 781, 825, 1276, 2538, 0, -124, -781, -825, -1276, -2538, 0],
// endgame material score
[0, 206, 854, 915, 1380, 2682, 0, -206, -854, -915, -1380, -2682, 0]
];
const openingPhaseScore = 15258;
const endgamePhaseScore = 3915;
const opening = 0, endgame = 1, middlegame = 2;
const PAWN = 0, KNIGHT = 1, BISHOP = 2, ROOK = 3, QUEEN = 4, KING = 5;
// piece-square tables
const pst = [
[
//pawn
[
0, 0, 0, 0, 0, 0, 0, 0, o, o, o, o, o, o, o, o,
-7, 7, -3, -13, 5, -16, 10, -8, o, o, o, o, o, o, o, o,
5, -12, -7, 22, -8, -5, -15, -8, o, o, o, o, o, o, o, o,
13, 0, -13, 1, 11, -2, -13, 5, o, o, o, o, o, o, o, o,
-4, -23, 6, 20, 40, 17, 4, -8, o, o, o, o, o, o, o, o,
-9, -15, 11, 15, 32, 22, 5, -22, o, o, o, o, o, o, o, o,
3, 3, 10, 19, 16, 19, 7, -5, o, o, o, o, o, o, o, o,
0, 0, 0, 0, 0, 0, 0, 0, o, o, o, o, o, o, o, o
],
// knight
[
-201, -83, -56, -26, -26, -56, -83,-201, o, o, o, o, o, o, o, o,
-67, -27, 4, 37, 37, 4, -27, -67, o, o, o, o, o, o, o, o,
-9, 22, 58, 53, 53, 58, 22, -9, o, o, o, o, o, o, o, o,
-34, 13, 44, 51, 51, 44, 13, -34, o, o, o, o, o, o, o, o,
-35, 8, 40, 49, 49, 40, 8, -35, o, o, o, o, o, o, o, o,
-61, -17, 6, 12, 12, 6, -17, -61, o, o, o, o, o, o, o, o,
-77, -41, -27, -15, -15, -27, -41, -77, o, o, o, o, o, o, o, o,
-175, -92, -74, -73, -73, -74, -92,-175, o, o, o, o, o, o, o, o
],
// bishop
[
-48, 1, -14, -23, -23, -14, 1, -48, o, o, o, o, o, o, o, o,
-17, -14, 5, 0, 0, 5, -14, -17, o, o, o, o, o, o, o, o,
-16, 6, 1, 11, 11, 1, 6, -16, o, o, o, o, o, o, o, o,
-12, 29, 22, 31, 31, 22, 29, -12, o, o, o, o, o, o, o, o,
-5, 11, 25, 39, 39, 25, 11, -5, o, o, o, o, o, o, o, o,
-7, 21, -5, 17, 17, -5, 21, -7, o, o, o, o, o, o, o, o,
-15, 8, 19, 4, 4, 19, 8, -15, o, o, o, o, o, o, o, o,
-53, -5, -8, -23, -23, -8, -5, -53, o, o, o, o, o, o, o, o
],
// rook
[
-17, -19, -1, 9, 9, -1, -19, -17, o, o, o, o, o, o, o, o
-2, 12, 16, 18, 18, 16, 12, -2, o, o, o, o, o, o, o, o,
-22, -2, 6, 12, 12, 6, -2, -22, o, o, o, o, o, o, o, o,
-27, -15, -4, 3, 3, -4, -15, -27, o, o, o, o, o, o, o, o,
-13, -5, -4, -6, -6, -4, -5, -13, o, o, o, o, o, o, o, o,
-25, -11, -1, 3, 3, -1, -11, -25, o, o, o, o, o, o, o, o,
-21, -13, -8, 6, 6, -8, -13, -21, o, o, o, o, o, o, o, o,
-31, -20, -14, -5, -5, -14, -20, -31, o, o, o, o, o, o, o, o
],
// queen
[
-2, -2, 1, -2, -2, 1, -2, -2, o, o, o, o, o, o, o, o,
-5, 6, 10, 8, 8, 10, 6, -5, o, o, o, o, o, o, o, o,
-4, 10, 6, 8, 8, 6, 10, -4, o, o, o, o, o, o, o, o,
0, 14, 12, 5, 5, 12, 14, 0, o, o, o, o, o, o, o, o,
4, 5, 9, 8, 8, 9, 5, 4, o, o, o, o, o, o, o, o,
-3, 6, 13, 7, 7, 13, 6, -3, o, o, o, o, o, o, o, o,
-3, 5, 8, 12, 12, 8, 5, -3, o, o, o, o, o, o, o, o,
3, -5, -5, 4, 4, -5, -5, 3, o, o, o, o, o, o, o, o
],
// king
[
59, 89, 45, -1, -1, 45, 89, 59, o, o, o, o, o, o, o, o,
88, 120, 65, 33, 33, 65, 120, 88, o, o, o, o, o, o, o, o,
123, 145, 81, 31, 31, 81, 145, 123, o, o, o, o, o, o, o, o,
154, 179, 105, 70, 70, 105, 179, 154, o, o, o, o, o, o, o, o,
164, 190, 138, 98, 98, 138, 190, 164, o, o, o, o, o, o, o, o,
195, 258, 169, 120, 120, 169, 258, 195, o, o, o, o, o, o, o, o,
278, 303, 234, 179, 179, 234, 303, 278, o, o, o, o, o, o, o, o,
271, 327, 271, 198, 198, 271, 327, 271, o, o, o, o, o, o, o, o
],
],
// Endgame positional piece scores //
[
//pawn
[
0, 0, 0, 0, 0, 0, 0, 0, o, o, o, o, o, o, o, o,
0, -11, 12, 21, 25, 19, 4, 7, o, o, o, o, o, o, o, o,
28, 20, 21, 28, 30, 7, 6, 13, o, o, o, o, o, o, o, o,
10, 5, 4, -5, -5, -5, 14, 9, o, o, o, o, o, o, o, o,
6, -2, -8, -4, -13, -12, -10, -9, o, o, o, o, o, o, o, o,
-10, -10, -10, 4, 4, 3, -6, -4, o, o, o, o, o, o, o, o,
-10, -6, 10, 0, 14, 7, -5, -19, o, o, o, o, o, o, o, o,
0, 0, 0, 0, 0, 0, 0, 0, o, o, o, o, o, o, o, o
],
// knight
[
-100, -88, -56, -17, -17, -56, -88,-100, o, o, o, o, o, o, o, o,
-69, -50, -51, 12, 12, -51, -50, -69, o, o, o, o, o, o, o, o,
-51, -44, -16, 17, 17, -16, -44, -51, o, o, o, o, o, o, o, o,
-45, -16, 9, 39, 39, 9, -16, -45, o, o, o, o, o, o, o, o,
-35, -2, 13, 28, 28, 13, -2, -35, o, o, o, o, o, o, o, o,
-40, -27, -8, 29, 29, -8, -27, -40, o, o, o, o, o, o, o, o,
-67, -54, -18, 8, 8, -18, -54, -67, o, o, o, o, o, o, o, o,
-96, -65, -49, -21, -21, -49, -65, -96, o, o, o, o, o, o, o, o
],
// bishop
[
-46, -42, -37, -24, -24, -37, -42, -46, o, o, o, o, o, o, o, o,
-31, -20, -1, 1, 1, -1, -20, -31, o, o, o, o, o, o, o, o,
-30, 6, 4, 6, 6, 4, 6, -30, o, o, o, o, o, o, o, o,
-17, -1, -14, 15, 15, -14, -1, -17, o, o, o, o, o, o, o, o,
-20, -6, 0, 17, 17, 0, -6, -20, o, o, o, o, o, o, o, o,
-16, -1, -2, 10, 10, -2, -1, -16, o, o, o, o, o, o, o, o,
-37, -13, -17, 1, 1, -17, -13, -37, o, o, o, o, o, o, o, o,
-57, -30, -37, -12, -12, -37, -30, -57, o, o, o, o, o, o, o, o
],
// rook
[
18, 0, 19, 13, 13, 19, 0, 18, o, o, o, o, o, o, o, o,
4, 5, 20, -5, -5, 20, 5, 4, o, o, o, o, o, o, o, o,
6, 1, -7, 10, 10, -7, 1, 6, o, o, o, o, o, o, o, o,
-5, 8, 7, -6, -6, 7, 8, -5, o, o, o, o, o, o, o, o,
-6, 1, -9, 7, 7, -9, 1, -6, o, o, o, o, o, o, o, o,
6, -8, -2, -6, -6, -2, -8, 6, o, o, o, o, o, o, o, o,
-12, -9, -1, -2, -2, -1, -9, -12, o, o, o, o, o, o, o, o,
-9, -13, -10, -9, -9, -10, -13, -9, o, o, o, o, o, o, o, o
],
// queen
[
-75, -52, -43, -36, -36, -43, -52, -75, o, o, o, o, o, o, o, o,
-50, -27, -24, -8, -8, -24, -27, -50, o, o, o, o, o, o, o, o,
-38, -18, -12, 1, 1, -12, -18, -38, o, o, o, o, o, o, o, o,
-29, -6, 9, 21, 21, 9, -6, -29, o, o, o, o, o, o, o, o,
-23, -3, 13, 24, 24, 13, -3, -23, o, o, o, o, o, o, o, o,
-39, -18, -9, 3, 3, -9, -18, -39, o, o, o, o, o, o, o, o,
-55, -31, -22, -4, -4, -22, -31, -55, o, o, o, o, o, o, o, o,
-69, -57, -47,- 26, 26, -47, -57, -69, o, o, o, o, o, o, o, o
],
// king
[
11, 59, 73, 78, 78, 73, 59, 11, o, o, o, o, o, o, o, o,
47, 121, 116, 131, 131, 116, 121, 47, o, o, o, o, o, o, o, o,
92, 172, 184, 191, 191, 184, 172, 92, o, o, o, o, o, o, o, o,
96, 166, 199, 199, 199, 199, 166, 96, o, o, o, o, o, o, o, o,
103, 156, 172, 172, 172, 172, 156, 103, o, o, o, o, o, o, o, o,
88, 130, 169, 175, 175, 169, 130, 88, o, o, o, o, o, o, o, o,
53, 100, 133, 135, 135, 133, 100, 53, o, o, o, o, o, o, o, o,
1, 45, 85, 76, 76, 85, 45, 1, o, o, o, o, o, o, o, o
]
]
];
// mirror positional score tables for opposite side
const mirrorSquare= [
a1, b1, c1, d1, e1, f1, g1, h1, o, o, o, o, o, o, o, o,
a2, b2, c2, d2, e2, f2, g2, h2, o, o, o, o, o, o, o, o,
a3, b3, c3, d3, e3, f3, g3, h3, o, o, o, o, o, o, o, o,
a4, b4, c4, d4, e4, f4, g4, h4, o, o, o, o, o, o, o, o,
a5, b5, c5, d5, e5, f5, g5, h5, o, o, o, o, o, o, o, o,
a6, b6, c6, d6, e6, f6, g6, h6, o, o, o, o, o, o, o, o,
a7, b7, c7, d7, e7, f7, g7, h7, o, o, o, o, o, o, o, o,
a8, b8, c8, d8, e8, f8, g8, h8, o, o, o, o, o, o, o, o
];
// insufficient material detection
function isMaterialDraw() {
if(pieceList[P] == 0 && pieceList[p] == 0) {
if (pieceList[R] == 0 && pieceList[r] == 0 && pieceList[Q] == 0 && pieceList[q] == 0) {
if (pieceList[B] == 0 && pieceList[b] == 0) {
if (pieceList[N] < 3 && pieceList[n] < 3)
return 1;
} else if (pieceList[N] == 0 && pieceList[n] == 0) {
if (Math.abs(pieceList[B] - pieceList[b]) < 2)
return 1;
} else if ((pieceList[N] < 3 && pieceList[B] == 0) || (pieceList[B] == 1 && pieceList[N] == 0)) {
if ((pieceList[n] < 3 && pieceList[b] == 0) || (pieceList[b] == 1 && pieceList[n] == 0))
return 1;
}
} else if (pieceList[Q] == 0 && pieceList[q] == 0) {
if (pieceList[R] == 1 && pieceList[r] == 1) {
if ((pieceList[N] + pieceList[B]) < 2 && (pieceList[n] + pieceList[b]) < 2) return 1;
} else if (pieceList[R] == 1 && pieceList[r] == 0) {
if ((pieceList[N] + pieceList[B] == 0) &&
(((pieceList[n] + pieceList[b]) == 1) ||
((pieceList[n] + pieceList[b]) == 2)))
return 1;
} else if (pieceList[r] == 1 && pieceList[R] == 0) {
if ((pieceList[n] + pieceList[b] == 0) &&
(((pieceList[N] + pieceList[B]) == 1) ||
((pieceList[N] + pieceList[B]) == 2)))
return 1;
}
}
}
return 0;
}
// get game phase
function getGamePhaseScore() {
let gamePhaseScore = 0;
for (let piece = N; piece <= Q; piece++) gamePhaseScore += pieceList[piece] * materialWeights[opening][piece];
for (let piece = n; piece <= q; piece++) gamePhaseScore += pieceList[piece] * -materialWeights[opening][piece];
return gamePhaseScore;
}
// static evaluation
function evaluate() {
if (isMaterialDraw()) return 0;
let gamePhaseScore = getGamePhaseScore();
let gamePhase = -1;
if (gamePhaseScore > openingPhaseScore) gamePhase = opening;
else if (gamePhaseScore < endgamePhaseScore) gamePhase = endgame;
else gamePhase = middlegame;
let score = 0;
var scoreOpening = 0;
var scoreEndgame = 0;
for (let piece = P; piece <= k; piece++) {
for (pieceIndex = 0; pieceIndex < pieceList[piece]; pieceIndex++) {
let square = pieceList.pieces[piece * 10 + pieceIndex];
// evaluate material
scoreOpening += materialWeights[opening][piece];
scoreEndgame += materialWeights[endgame][piece];
// positional score
switch (piece) {
case P:
scoreOpening += pst[opening][PAWN][square];
scoreEndgame += pst[endgame][PAWN][square];
break;
case N:
scoreOpening += pst[opening][KNIGHT][square];
scoreEndgame += pst[endgame][KNIGHT][square];
break;
case B:
scoreOpening += pst[opening][BISHOP][square];
scoreEndgame += pst[endgame][BISHOP][square];
break;
case R:
scoreOpening += pst[opening][ROOK][square];
scoreEndgame += pst[endgame][ROOK][square];
break;
case Q:
scoreOpening += pst[opening][QUEEN][square];
scoreEndgame += pst[endgame][QUEEN][square];
break;
case K:
scoreOpening += pst[opening][KING][square];
scoreEndgame += pst[endgame][KING][square];
break;
case p:
scoreOpening -= pst[opening][PAWN][mirrorSquare[square]];
scoreEndgame -= pst[endgame][PAWN][mirrorSquare[square]];
break;
case n:
scoreOpening -= pst[opening][KNIGHT][mirrorSquare[square]];
scoreEndgame -= pst[endgame][KNIGHT][mirrorSquare[square]];
break;
case b:
scoreOpening -= pst[opening][BISHOP][mirrorSquare[square]];
scoreEndgame -= pst[endgame][BISHOP][mirrorSquare[square]];
break;
case r:
scoreOpening -= pst[opening][ROOK][mirrorSquare[square]];
scoreEndgame -= pst[endgame][ROOK][mirrorSquare[square]];
break;
case q:
scoreOpening -= pst[opening][QUEEN][mirrorSquare[square]];
scoreEndgame -= pst[endgame][QUEEN][mirrorSquare[square]];
break;
case k:
scoreOpening -= pst[opening][KING][mirrorSquare[square]];
scoreEndgame -= pst[endgame][KING][mirrorSquare[square]];
break;
}
}
}
// interpolate score in the middlegame
if (gamePhase == middlegame)
score = (
scoreOpening * gamePhaseScore +
scoreEndgame * (openingPhaseScore - gamePhaseScore)
) / openingPhaseScore;
else if (gamePhase == opening) score = scoreOpening;
else if (gamePhase == endgame) score = scoreEndgame;
score = Math.round(score * (100 - fifty) / 100);
return (side == white) ? score: -score;
}
