Skip to content

Commit

Permalink
Human playable levels
Browse files Browse the repository at this point in the history
Level=0 (default) disables levels (ie. full strength).

Level L uses:
* depth = L <= 10 ? L : 2 * L - 10
* nodes = 2 ^ (L + 5) = 32 << L
* noise ~ Logistic(0, s), with:
  s = 200 * 0.8 ^ (L - 1) * phaseFactor
  phaseFactor = 1.0 when stm has all pieces, and 0.5 when stm has no pieces (excl. King and Pawns), linearly in between
  • Loading branch information
lucasart committed Oct 4, 2021
1 parent bd73367 commit 5b0da45
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 128 deletions.
21 changes: 20 additions & 1 deletion src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "bitboard.h"
#include "position.h"
#include "tune.h"
#include "uci.h"
#include "util.h"
#include <math.h>
#include <stdlib.h>
Expand Down Expand Up @@ -391,5 +392,23 @@ int evaluate(Worker *worker, const Position *pos) {
stm.eg -= stm.eg * discount[bb_count(winnerPawns)] / 8;
}

return blend(pos, stm);
int result = blend(pos, stm);

if (uciLevel) {
// Draw 0 < p < 1
double p = 0;
while (p <= 0 || p >= 1)
p = prngf(&worker->seed);

// Scale down noise towards the endgame
const double phaseFactor = 0.5 + (double)pos->pieceMaterial[pos->turn] / StartPieceTotal;

// scale parameter of centered logistic: CDF(x) = 1 / (1 + exp(-x/s))
const double s = 200 * pow(0.8, uciLevel - 1) * phaseFactor;

// Add logistic drawing as eval noise
result += s * log(p / (1 - p));
}

return result;
}
68 changes: 10 additions & 58 deletions src/tune.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,71 +53,23 @@ eval_t PawnPstSeed[6][4] = {
{{-1, 8}, {12, 3}, {-9, -4}, {-2, 5}}, {{-6, -3}, {2, 1}, {-4, -2}, {2, 1}},
};

// clang-format off
eval_t Mobility[5][15] = {
// Knight
{{-38, -48}, {-18, -30}, {-15, -21}, {4, 0}, {9, 16}, {20, 34}, {34, 28}, {35, 46}, {29, 47}},
// Bishop
{{-66, -70},
{-42, -35},
{-16, -30},
{-7, -19},
{12, -2},
{24, 16},
{37, 33},
{27, 50},
{41, 55},
{45, 65},
{55, 37},
{71, 65},
{71, 56},
{120, 95}},
{{-66, -70}, {-42, -35}, {-16, -30}, {-7, -19}, {12, -2}, {24, 16}, {37, 33}, {27, 50},
{41, 55}, {45, 65}, {55, 37}, {71, 65}, {71, 56}, {120, 95}},
// Rook
{{-60, -46},
{-33, -51},
{-19, -28},
{-6, -22},
{-5, -3},
{-5, 1},
{9, 2},
{19, 5},
{27, 19},
{41, 38},
{57, 33},
{56, 40},
{48, 43},
{57, 48},
{72, 56}},
{{-60, -46}, {-33, -51}, {-19, -28}, {-6, -22}, {-5, -3}, {-5, 1}, {9, 2}, {19, 5}, {27, 19},
{41, 38}, {57, 33}, {56, 40}, {48, 43}, {57, 48}, {72, 56}},
// Queen diagonal
{{-27, -41},
{-9, -29},
{-12, -4},
{-4, -8},
{0, -1},
{11, 13},
{11, 23},
{17, 41},
{13, 13},
{23, 47},
{28, 50},
{34, 24},
{16, 32},
{24, 87}},
{{-27, -41}, {-9, -29}, {-12, -4}, {-4, -8}, {0, -1}, {11, 13}, {11, 23}, {17, 41}, {13, 13},
{23, 47}, {28, 50}, {34, 24}, {16, 32}, {24, 87}},
// Queen orthogonal
{{-24, -64},
{-19, -25},
{-16, -11},
{-9, -4},
{-2, -10},
{4, -10},
{2, 16},
{9, 14},
{13, 14},
{21, 26},
{8, 37},
{21, 43},
{25, 48},
{19, 45},
{24, 54}}};
{{-24, -64}, {-19, -25}, {-16, -11}, {-9, -4}, {-2, -10}, {4, -10}, {2, 16}, {9, 14}, {13, 14},
{21, 26}, {8, 37}, {21, 43}, {25, 48}, {19, 45}, {24, 54}}};
// clang-format on

int RookOpen[2] = {20, 33}; // 0: semi-open, 1: fully-open
eval_t BishopPair = {77, 122};
Expand Down
74 changes: 10 additions & 64 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,73 +35,19 @@
enum { RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, NB_RANK };
enum { FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, NB_FILE };

// clang-format off
enum {
A1,
B1,
C1,
D1,
E1,
F1,
G1,
H1,
A2,
B2,
C2,
D2,
E2,
F2,
G2,
H2,
A3,
B3,
C3,
D3,
E3,
F3,
G3,
H3,
A4,
B4,
C4,
D4,
E4,
F4,
G4,
H4,
A5,
B5,
C5,
D5,
E5,
F5,
G5,
H5,
A6,
B6,
C6,
D6,
E6,
F6,
G6,
H6,
A7,
B7,
C7,
D7,
E7,
F7,
G7,
H7,
A8,
B8,
C8,
D8,
E8,
F8,
G8,
H8,
A1, B1, C1, D1, E1, F1, G1, H1,
A2, B2, C2, D2, E2, F2, G2, H2,
A3, B3, C3, D3, E3, F3, G3, H3,
A4, B4, C4, D4, E4, F4, G4, H4,
A5, B5, C5, D5, E5, F5, G5, H5,
A6, B6, C6, D6, E6, F6, G6, H6,
A7, B7, C7, D7, E7, F7, G7, H7,
A8, B8, C8, D8, E8, F8, G8, H8,
NB_SQUARE
};
// clang-format on

enum { UP = 8, DOWN = -8, LEFT = -1, RIGHT = 1 };

Expand Down
12 changes: 10 additions & 2 deletions src/uci.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
static pthread_t Timer = 0;

size_t uciHash = 2;
int uciLevel = 0;
int64_t uciTimeBuffer = 60;
bool uciChess960 = false;

Expand All @@ -45,6 +46,7 @@ static void intro(void) {
uci_printf("option name Contempt type spin default %d min -100 max 100\n", Contempt);
uci_printf("option name Hash type spin default %zu min 1 max 1048576\n", uciHash);
uci_puts("option name Ponder type check default false");
uci_printf("option name Level type spin default %d min 0 max 15\n", uciLevel);
uci_printf("option name Threads type spin default %zu min 1 max 256\n", WorkersCount);
uci_printf("option name Time Buffer type spin default %" PRId64 " min 0 max 1000\n",
uciTimeBuffer);
Expand Down Expand Up @@ -77,6 +79,8 @@ static void setoption(char **linePos) {
workers_prepare((size_t)atoll(token));
else if (!strcmp(name, "Contempt"))
Contempt = atoi(token);
else if (!strcmp(name, "Level"))
uciLevel = atoi(token);
else if (!strcmp(name, "TimeBuffer"))
uciTimeBuffer = atoi(token);
else {
Expand Down Expand Up @@ -118,8 +122,12 @@ static void position(char **linePos) {
}

static void go(char **linePos) {
lim = (Limits){0};
lim.depth = MAX_DEPTH;
lim = (Limits){.depth = MAX_DEPTH};

if (uciLevel) {
lim.depth = uciLevel <= 10 ? uciLevel : 2 * uciLevel - 10;
lim.nodes = 32ULL << uciLevel;
}

const char *token;

Expand Down
1 change: 1 addition & 0 deletions src/uci.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ typedef struct {
} Info;

extern Info ui;
extern int uciLevel;
extern int64_t uciTimeBuffer;
extern bool uciChess960;
extern size_t uciHash;
Expand Down
4 changes: 4 additions & 0 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ uint64_t prng(uint64_t *state) {
return rnd;
}

double prngf(uint64_t *state) {
return (prng(state) >> 11) * 0x1.0p-53;
}

void hash_block(uint64_t block, uint64_t *hash) {
*hash ^= hash_mix(block);
*hash *= 0x880355f21e6d1965ULL;
Expand Down
2 changes: 2 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
#include <stddef.h>

uint64_t prng(uint64_t *state);
double prngf(uint64_t *state);

void hash_block(uint64_t block, uint64_t *hash);
void hash_blocks(const void *buffer, size_t length, uint64_t *hash);
14 changes: 11 additions & 3 deletions src/workers.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
* You should have received a copy of the GNU General Public License along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*/
#include "workers.h"
#include "platform.h"
#include "search.h"
#include "workers.h"
#include <stdlib.h>

Worker *Workers = NULL;
Expand All @@ -22,13 +23,20 @@ size_t WorkersCount = 1;
static void __attribute__((destructor)) workers_free(void) { free(Workers); }

void workers_clear() {
for (size_t i = 0; i < WorkersCount; i++)
Workers[i] = (Worker){0};
for (size_t i = 0; i < WorkersCount; i++) {
// Clear Workers[i] except .seed, which must be preserved
uint64_t saveSeed = Workers[i].seed;
Workers[i] = (Worker){.seed = saveSeed};
}
}

void workers_prepare(size_t count) {
Workers = realloc(Workers, count * sizeof(Worker));
WorkersCount = count;

for (size_t i = 0; i < count; i++)
Workers[i].seed = (uint64_t)system_msec() + i;

workers_clear();
}

Expand Down
1 change: 1 addition & 0 deletions src/workers.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ typedef struct {
ZobristStack stack;
jmp_buf jbuf;
uint64_t nodes;
uint64_t seed;
int eval[MAX_PLY];
} Worker;

Expand Down

0 comments on commit 5b0da45

Please sign in to comment.