diff --git a/.gitignore b/.gitignore index b1af79a..ccaafa9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ src/version.h .* chess2 test/test +tuning/tuning diff --git a/Makefile b/Makefile index bb7e619..335d4e7 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ cleanextras: iwyuextras: cd src && make iwyu && cd .. + cd tuning && make iwyu && cd .. chess2: $(obj) $(CC) $(CFLAGS) -o $@ $^ src/*.o diff --git a/main.c b/main.c index 678fb9a..fec549b 100644 --- a/main.c +++ b/main.c @@ -46,6 +46,7 @@ void print_bitboard(BITBOARD bb) { } int stopped = 0; +int nodes; int main(int argc, char *argv[]) { diff --git a/scripts/tune_db_extract.py b/scripts/tune_db_extract.py new file mode 100644 index 0000000..5a998a8 --- /dev/null +++ b/scripts/tune_db_extract.py @@ -0,0 +1,23 @@ +# extract epd database from pgn generated by cutechess for tuning +# cutechess/cutechess-cli -each tc=1/1+0.08 proto=uci -engine cmd=chess-2/chess2_latest book=openings.bin -engine cmd=chess-2/chess2_other book=openings.bin -rounds 60000 -concurrency 4 -pgnout games_fast.pgn -recover & +import chess.pgn + +fn = 'games_fast.pgn' + +with open(fn, encoding='utf-8') as h: + while True: + game = chess.pgn.read_game(h) + if game is None: + break + + for node in game.mainline(): + comment = node.comment + if comment=='book': + pass + elif comment.startswith('+100.00') or comment.startswith('-100.00'): + pass + else: + fen = node.board().fen() + result = game.headers[ 'Result' ] + if result == '1-0' or result == '0-1' or result == '1/2-1/2': + print(f'{fen} {result}') diff --git a/src/board.c b/src/board.c index d0c2979..ec8cdd3 100644 --- a/src/board.c +++ b/src/board.c @@ -4,7 +4,6 @@ #include "board.h" #include "move.h" -#include "movegen.h" #include "moveexec.h" #include "zobrist.h" @@ -153,7 +152,7 @@ void play_uci_moves(BOARD * board, const char * moves) { } else if (piece == KING && ((ff - tf) == 2 || (tf - ff) == 2)) { unsigned index = ((fr & BLACK) << 1) | (ff < tf ? 0 : 1); - castle = castling_rook_from_to(index); + castle = castle_rook_from_to[index]; } move.from = from; @@ -285,3 +284,23 @@ HASH calculate_hash(const BOARD * board) { return result; } +CASTLE castle_update(const BOARD * board, PIECE piece, BITBOARD fromto) { + CASTLE castle = + ((fromto & ((BITBOARD)1 << 0)) << 1) | ((fromto & ((BITBOARD)1 << 7)) >> 7) | + ((fromto & ((BITBOARD)1 << 56)) >> 53) | ((fromto & ((BITBOARD)1 << 63)) >> 61); + + if (piece == KING) { + castle |= CASTLES_OF(board->next); + } + + return board->castle ^ (board->castle & ~castle); +} + +const BITBOARD castle_king_from_to[4] = { + 0x0000000000000050, 0x0000000000000014, 0x5000000000000000, 0x1400000000000000 +}; + +const BITBOARD castle_rook_from_to[4] = { + 0x00000000000000a0, 0x0000000000000009, 0xa000000000000000, 0x0900000000000000 +}; + diff --git a/src/board.h b/src/board.h index db2e7a3..efcad38 100644 --- a/src/board.h +++ b/src/board.h @@ -44,4 +44,8 @@ void print_board(const BOARD* board); void print_fen(const BOARD* board); HASH calculate_hash(const BOARD* board); +CASTLE castle_update(const BOARD * board, PIECE piece, BITBOARD fromto); +extern const BITBOARD castle_rook_from_to[4]; +extern const BITBOARD castle_king_from_to[4]; + #endif /* ifndef _BOARD_H_ */ diff --git a/src/chess.h b/src/chess.h index 264ac2c..42730b2 100644 --- a/src/chess.h +++ b/src/chess.h @@ -47,7 +47,7 @@ typedef enum { NO_PIECE_V = 0, PAWN_V = 100, KNIGHT_V = 300, - BISHOP_V = 300, + BISHOP_V = 340, ROOK_V = 500, QUEEN_V = 900, KING_V = 10000 } PIECE_VALUE; diff --git a/src/evaluate.c b/src/evaluate.c index babc086..bee5a1a 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1,6 +1,8 @@ #include +#include #include "evaluate.h" +#include "tuned_values.h" #include "pawns.h" #include "board.h" #include "mat_tables.h" @@ -113,6 +115,9 @@ int evaluate(const BOARD * board) { int dir[] = {1, -1}; const MAT_TABLE_ENTRY * mt = get_mat_table_entry(board); SQUARE kings[6]; + int gp = mt->flags & ENDGAME_MASK; + + assert(0 <= gp && gp <= 3); if (mt->flags & DRAWN) { return 0; @@ -125,7 +130,6 @@ int evaluate(const BOARD * board) { for (COLOUR colour = WHITE; colour <= BLACK; colour++) { int pawn_value = 0; - static const int rank_values[] = {0, 30, 35, 45, 65, 105, 185, 270}; BITBOARD my_pawns = board->pawns & COLOUR_BB(board, colour); BITBOARD their_pawns = board->pawns & COLOUR_BB(board, 1 - colour); @@ -138,19 +142,19 @@ int evaluate(const BOARD * board) { DEBUG_PRINT("%s passer\t\t%8.8lx\n", colour_names[colour], pass); DEBUG_PRINT("%s weak\t\t%8.8lx\n", colour_names[colour], wk); - pawn_value += piece_values[PAWN] * __builtin_popcountll(my_pawns); - pawn_value -= 20 * __builtin_popcountll(iso); + pawn_value += tuned_values[gp].piece_v_pawn_v * __builtin_popcountll(my_pawns); + pawn_value += tuned_values[gp].pawn_isolated * __builtin_popcountll(iso); while (pass) { BITBOARD isolated = pass & -pass; SQUARE sq = __builtin_ctzll(isolated); SQUARE rank = sq >> 3; SQUARE erank = colour == WHITE ? rank : 7 - rank; - pawn_value += rank_values[erank]; + pawn_value += *(&tuned_values[gp].pawn_ranks_0 + erank); pass &= pass - 1; } - pawn_value -= 10 * __builtin_popcountll(wk); + pawn_value += tuned_values[gp].pawn_weak * __builtin_popcountll(wk); DEBUG_PRINT("%s pawn\t\t%d\n", colour_names[colour], pawn_value); @@ -160,6 +164,7 @@ int evaluate(const BOARD * board) { for (COLOUR colour = WHITE; colour <= BLACK; colour++) { for (PIECE piece = PAWN + 1; piece < KING; ++piece) { BITBOARD pieces = *(&board->pawns + piece - PAWN) & COLOUR_BB(board, colour); + int piece_value = *(&tuned_values[gp].piece_v_pawn_v + piece - PAWN); while (pieces) { BITBOARD single = pieces & -pieces; @@ -169,13 +174,13 @@ int evaluate(const BOARD * board) { if (colour == WHITE) { sq = ((7 - rank) << 3) | file; - value += piece_values[piece] + bonuses[piece][sq]; + value += piece_value + bonuses[piece][sq]; } else { - value -= piece_values[piece] + bonuses[piece][sq]; + value -= piece_value + bonuses[piece][sq]; } DEBUG_PRINT("%s %s\t\t%d\n", - colour_names[colour], piece_names[piece], piece_values[piece] + bonuses[piece][sq]); + colour_names[colour], piece_names[piece], piece_value + bonuses[piece][sq]); pieces &= pieces - 1; } @@ -237,13 +242,13 @@ static inline int king_evaluate(const MAT_TABLE_ENTRY * mt, COLOUR colour, SQUAR SQUARE sq = sqs[colour]; /* default - piece square interpolate between middle game - endgame */ - endgame_factor = mt->flags & ENDGAME_MASK; - static const int shield_value[] = { -40, -20, 0, 0 }; + int gp = mt->flags & ENDGAME_MASK; + int shield_value = tuned_values[gp].king_shield; int safety = __builtin_popcountll( shield((board->pawns | board->bishops) & COLOUR_BB(board, colour), /* fianchettoed bishops */ colour, board->kings & COLOUR_BB(board, colour)) - ) * shield_value[endgame_factor]; + ) * shield_value; DEBUG_PRINT("%s king shield\t%d\n", colour_names[colour], safety); static const int mdl_psqt_weight[] = { 2, 2, 1, 0}; diff --git a/src/mat_tables.c b/src/mat_tables.c index 7cb3803..6751e64 100644 --- a/src/mat_tables.c +++ b/src/mat_tables.c @@ -125,10 +125,12 @@ static const RULE rules[] = { { "0 0 0 0 0 0 0 0 0 0 a b", { 0, B_CHECKMATING} }, { NULL, { 0, CONSTRAINT } }, +#if 0 + /* WP WN WB_LSQ WB_DSQ WR WQ BP BN BB_LSQ BB_DSQ BR BQ V F */ { "a+1=b ", { 0, CONSTRAINT } }, - { "a 0 1 0 0 0 b 0 0 1 0 0", { PAWN_V, 0} }, /* opposite colour bishop endgames */ - { "b 0 1 0 0 0 a 0 0 1 0 0", { -1*PAWN_V, 0} }, /* 1 pawn diff: take away the pawn */ + { "a 0 1 0 0 0 b 0 0 1 0 0", { 100, 0} }, /* opposite colour bishop endgames */ + { "b 0 1 0 0 0 a 0 0 1 0 0", { -100, 0} }, /* 1 pawn diff: take away the pawn */ { "a+2=b ", { 0, CONSTRAINT } }, { "a 0 1 0 0 0 b 0 0 1 0 0", { 80, 0} }, /* 2 pawn diff: take away less than a pawn */ { "b 0 1 0 0 0 a 0 0 1 0 0", { -80, 0} }, /* 3 pawn diff: should be winning? */ @@ -201,6 +203,7 @@ static const RULE rules[] = { { "b+c+d+e+f=6 ", { 0, CONSTRAINT } }, { ">a b c d e f a b c d e f", { 5, 0} }, { NULL, { 0, CONSTRAINT } }, +#endif { NULL, { 0, 0} } }; diff --git a/src/movegen.c b/src/movegen.c index a7d9d0d..982bbe6 100644 --- a/src/movegen.c +++ b/src/movegen.c @@ -11,6 +11,7 @@ #include "board.h" #include "movelist.h" #include "attacks.h" +#include "tuned_values.h" typedef enum { MOVEGEN_START = 0, @@ -74,18 +75,6 @@ static BITBOARD normal_attacks(const BOARD * board, PIECE piece, SQUARE sq, BITB } } -CASTLE castle_update(const BOARD * board, PIECE piece, BITBOARD fromto) { - CASTLE castle = - ((fromto & ((BITBOARD)1 << 0)) << 1) | ((fromto & ((BITBOARD)1 << 7)) >> 7) | - ((fromto & ((BITBOARD)1 << 56)) >> 53) | ((fromto & ((BITBOARD)1 << 63)) >> 61); - - if (piece == KING) { - castle |= CASTLES_OF(board->next); - } - - return board->castle ^ (board->castle & ~castle); -} - /* knight, bishop, rook, queen and king moves excluding specials like castling */ static void add_normal_moves(const BOARD * board, PIECE piece, BITBOARD allowed_targets) { BITBOARD colour = NEXT_COLOUR_BB(board); @@ -267,17 +256,6 @@ void add_pawn_pushes(const BOARD * board) { } } -static const BITBOARD castle_king_from_to[4] = { - 0x0000000000000050, 0x0000000000000014, 0x5000000000000000, 0x1400000000000000 -}; - -static const BITBOARD castle_rook_from_to[4] = { - 0x00000000000000a0, 0x0000000000000009, 0xa000000000000000, 0x0900000000000000 -}; - -BITBOARD castling_rook_from_to(CASTLE castle) { - return castle_rook_from_to[castle]; -} /* from 0000...010.....010.... you get * 0000000001111111000000 diff --git a/src/movegen.h b/src/movegen.h index 1a6e481..4833a5c 100644 --- a/src/movegen.h +++ b/src/movegen.h @@ -2,7 +2,6 @@ #define _MOVEGEN_H_ #include "board.h" -#include "chess.h" #include "move.h" #include "killer.h" #include "pv.h" @@ -38,8 +37,4 @@ MOVE * moves(const BOARD * board, int ply, const PV * pv, const KILLER * killer, /* call if a search returns early - before moves() returning NULL */ void moves_done(int ply); -/* TODO move these */ -CASTLE castle_update(const BOARD * board, PIECE piece, BITBOARD fromto); -BITBOARD castling_rook_from_to(CASTLE castle); - #endif /* ifndef _MOVEGEN_H_ */ diff --git a/src/search.c b/src/search.c index b3f453c..e2d85ef 100644 --- a/src/search.c +++ b/src/search.c @@ -17,7 +17,7 @@ #include "chess.h" static struct timespec start; -unsigned long long nodes; +extern unsigned long long nodes; #define STDIN 0 int check_for_input(void) { diff --git a/src/search.h b/src/search.h index 991950e..0f45cf2 100644 --- a/src/search.h +++ b/src/search.h @@ -7,6 +7,8 @@ extern unsigned long long nodes; +int quiesce(BOARD * board, int ply, int alpha, int beta); + int negascout(BOARD* board, int ply, int depth, diff --git a/src/see.c b/src/see.c index 714b3a8..f34cfc2 100644 --- a/src/see.c +++ b/src/see.c @@ -4,12 +4,6 @@ #include "see.h" #include "attacks.h" -/* make bishops worth more because the evaluation gives bonuses to bishop pairs, - * so we have a better chance of getting the order right - * thus beta cutting more - **/ -static const int piece_values_mod[] = {NO_PIECE_V, PAWN_V, KNIGHT_V, BISHOP_V + 40, ROOK_V, QUEEN_V, KING_V}; - int see(const BOARD * board, const MOVE * move) { BITBOARD from = move->from; BITBOARD to = move->to; @@ -119,7 +113,7 @@ int see(const BOARD * board, const MOVE * move) { ply--; for (ply--; ply >= 0; ply--) { value = MAX(value, 0); - value = piece_values_mod[captures[ply]] - value; + value = piece_values[captures[ply]] - value; } /* THE END */ diff --git a/src/tuned_values.c b/src/tuned_values.c new file mode 100644 index 0000000..ba3d396 --- /dev/null +++ b/src/tuned_values.c @@ -0,0 +1,76 @@ +#include "tuned_values.h" + +const TUNED_VALUES tuned_values[4] = { + { + 100, /* piece_v_pawn_v */ + 159, /* piece_v_knight_v */ + 169, /* piece_v_bishop_v */ + 367, /* piece_v_rook_v */ + 728, /* piece_v_queen_v */ + 0, /* pawn_ranks_0 */ + 49, /* pawn_ranks_1 */ + 25, /* pawn_ranks_2 */ + 1, /* pawn_ranks_3 */ + 11, /* pawn_ranks_4 */ + 83, /* pawn_ranks_5 */ + 186, /* pawn_ranks_6 */ + 270, /* pawn_ranks_7 */ + -8, /* pawn_isolated */ + -9, /* pawn_weak */ + -2, /* king_shield_0 */ + }, + { + 100, /* piece_v_pawn_v */ + 159, /* piece_v_knight_v */ + 169, /* piece_v_bishop_v */ + 367, /* piece_v_rook_v */ + 728, /* piece_v_queen_v */ + 0, /* pawn_ranks_0 */ + 49, /* pawn_ranks_1 */ + 25, /* pawn_ranks_2 */ + 1, /* pawn_ranks_3 */ + 11, /* pawn_ranks_4 */ + 83, /* pawn_ranks_5 */ + 186, /* pawn_ranks_6 */ + 270, /* pawn_ranks_7 */ + -8, /* pawn_isolated */ + -9, /* pawn_weak */ + -25, /* king_shield_1 */ + }, + { + 100, /* piece_v_pawn_v */ + 159, /* piece_v_knight_v */ + 169, /* piece_v_bishop_v */ + 367, /* piece_v_rook_v */ + 728, /* piece_v_queen_v */ + 0, /* pawn_ranks_0 */ + 49, /* pawn_ranks_1 */ + 25, /* pawn_ranks_2 */ + 1, /* pawn_ranks_3 */ + 11, /* pawn_ranks_4 */ + 83, /* pawn_ranks_5 */ + 186, /* pawn_ranks_6 */ + 270, /* pawn_ranks_7 */ + -8, /* pawn_isolated */ + -9, /* pawn_weak */ + 5, /* king_shield_2 */ + }, + { + 100, /* piece_v_pawn_v */ + 159, /* piece_v_knight_v */ + 169, /* piece_v_bishop_v */ + 367, /* piece_v_rook_v */ + 728, /* piece_v_queen_v */ + 0, /* pawn_ranks_0 */ + 49, /* pawn_ranks_1 */ + 25, /* pawn_ranks_2 */ + 1, /* pawn_ranks_3 */ + 11, /* pawn_ranks_4 */ + 83, /* pawn_ranks_5 */ + 186, /* pawn_ranks_6 */ + 270, /* pawn_ranks_7 */ + -8, /* pawn_isolated */ + -9, /* pawn_weak */ + -9, /* king_shield_3 */ + }, +}; diff --git a/src/tuned_values.h b/src/tuned_values.h new file mode 100644 index 0000000..a8935a5 --- /dev/null +++ b/src/tuned_values.h @@ -0,0 +1,32 @@ +#ifndef __TUNED_VALUES_H__ +#define __TUNED_VALUES_H__ + +typedef struct __TUNED_VALUES__ { + int piece_v_pawn_v; + int piece_v_knight_v; + int piece_v_bishop_v; + int piece_v_rook_v; + int piece_v_queen_v; + + int pawn_ranks_0; + int pawn_ranks_1; + int pawn_ranks_2; + int pawn_ranks_3; + int pawn_ranks_4; + int pawn_ranks_5; + int pawn_ranks_6; + int pawn_ranks_7; + + int pawn_isolated; + int pawn_weak; + + int king_shield; +} TUNED_VALUES; + +#if defined(TUNING) +extern TUNED_VALUES tuned_values[4]; +#else +extern const TUNED_VALUES tuned_values[4]; +#endif + +#endif /* ifndef __TUNED_VALUES_H__ */ diff --git a/test/main.c b/test/main.c index b1cc5fe..0b43b76 100644 --- a/test/main.c +++ b/test/main.c @@ -20,6 +20,7 @@ #include "evaluate_tests.h" int stopped = 0; +unsigned long long nodes = 0; static void perft_unit_test1(void **state) { BOARD * b = initial_board(); diff --git a/test/mat_tables_tests.c b/test/mat_tables_tests.c index e595245..fffdb94 100644 --- a/test/mat_tables_tests.c +++ b/test/mat_tables_tests.c @@ -200,7 +200,7 @@ void mat_tables_test16(void **state) { board = parse_fen("5bk1/5pp1/8/8/8/8/4KPB1/8 w - - 0 1"); e = get_mat_table_entry(board); - assert_int_equal(e->value, PAWN_V); + assert_int_equal(e->value, 100); free(board); } diff --git a/tuning/Makefile b/tuning/Makefile new file mode 100644 index 0000000..e97349f --- /dev/null +++ b/tuning/Makefile @@ -0,0 +1,22 @@ +CFLAGS=-DTUNING -I../src -I. + +include ../makefile.mk + +buildpreobj: evaluate.o srcbuild + +.PHONY: +srcbuild: + cd ../src && make && cd .. + +evaluate.o: ../src/evaluate.c + $(CC) -c $(CFLAGS) $^ -o $@ + +buildpostobj: tuning + +srcobjs=$(filter-out ../src/evaluate.o ../src/tuned_values.o, $(wildcard ../src/*.o)) + +tuning: $(obj) + $(CC) $(CFLAGS) -lm -o $@ $^ evaluate.o $(srcobjs) + +cleanextras: + rm -f evaluate.o tuning diff --git a/tuning/main.c b/tuning/main.c new file mode 100644 index 0000000..10846c9 --- /dev/null +++ b/tuning/main.c @@ -0,0 +1,213 @@ +/* Texel's tuning method */ +/* https://www.chessprogramming.org/Texel%27s_Tuning_Method */ + +#include +#include +#include +#include + +#include "board.h" +#include "search.h" +#include "evaluate.h" +#include "mat_tables.h" +#include "tuned_values.h" + +TUNED_VALUES tuned_values[4] = { + /* (a) : passer rank 0 + * (b) : passer rank 1 + * (c) : passer rank 2 + * (d) : passer rank 3 + * (e) : passer rank 4 + * (f) : passer rank 5 + * (g) : passer rank 6 + * (h) : passer rank 7 + * (i) : isolated pawn + * (j) : weak pawn + * (k) : king shield + */ + /* P N B R Q (a) (b) (c) (d) (e) (f) (g) (h) (i) (j) (k) */ + { 100, 300, 340, 500, 900, 0, 49, 25, 1, 11, 83, 186, 270, -8, -9, -2 }, /* game phase (0) */ + { 100, 300, 340, 500, 900, 0, 49, 25, 1, 11, 83, 186, 270, -8, -9, -25 }, /* game phase (1) */ + { 100, 300, 340, 500, 900, 0, 49, 25, 1, 11, 83, 186, 270, -8, -9, -25 }, /* game phase (2) */ + { 100, 300, 340, 500, 900, 0, 49, 25, 1, 11, 83, 186, 270, -8, -9, -9 }, /* game phase (3) */ +}; + +static float get_result(char * buffer) { + int spaces = 0; + char * ptr = buffer; + + /* go to 7th column */ + while (* ptr) { + if (spaces == 6) break; + if (*ptr == ' ') spaces++; + ptr++; + } + + if (strncmp(ptr, "1-0", 3) == 0) { + return 1.0; + } else if (strncmp(ptr, "0-1", 3) == 0) { + return 0.0; + } else if (strncmp(ptr, "1/2-1/2", 7) == 0) { + return 0.5; + } else { + printf("'%s' was invalid, no result string\n", buffer); + abort(); + } + + return 0; +} + +static COLOUR get_side_to_move(char * buffer) { + int spaces = 0; + + /* go to 2nd column */ + while (* buffer) { + if (spaces == 1) break; + if (*buffer == ' ') spaces++; + buffer++; + } + + if (strncmp(buffer, "w", 1) == 0) { + return WHITE; + } else if (strncmp(buffer, "b", 1) == 0) { + return BLACK; + } else { + printf("'%s' was invalid, no side to move\n", buffer); + abort(); + } + + return 0; +} + +static float sigmoid(int score) { + return 1.0 / (1 + powf(10.0, (-1.0 * score) / 400.0)); +} + +static float error(FILE * epd) { + rewind(epd); + char buffer[1024]; + float error_sum = 0; + int count = 0; + + while (NULL != fgets(buffer, 1024, epd)) { + BOARD * board; + int score; + float result; + COLOUR stm; + float error; + + board = parse_fen(buffer); + result = get_result(buffer); + stm = get_side_to_move(buffer); + + score = quiesce(board, 0, -10000, 10000); + if (stm == BLACK) { + score *= -1; + } + + error = powf(result - sigmoid(score), 2); + error_sum += error; + count++; + + free(board); + + /* printf("score: %d\t\tresult: %f error: %f\n", score, result, error); */ + } + + return error_sum / count; +} + +static void print_values(void) { + printf( + "TUNED_VALUES tuned_values[4] = { {\n" + " /* (a) : passer rank 0\n" + " * (b) : passer rank 1\n" + " * (c) : passer rank 2\n" + " * (d) : passer rank 3\n" + " * (e) : passer rank 4\n" + " * (f) : passer rank 5\n" + " * (g) : passer rank 6\n" + " * (h) : passer rank 7\n" + " * (i) : isolated pawn\n" + " * (j) : weak pawn\n" + " * (k) : king shield\n" + " */\n" + " /* P N B R Q (a) (b) (c) (d) (e) (f) (g) (h) (i) (j) (k) */\n"); + for (int i = 0; i < 4; ++i) { + printf(" {"); + for (int j = 0; j < sizeof(tuned_values[0]) / sizeof(int); ++j) { + char buf[4]; + snprintf(buf, 4, "%d", *(&tuned_values[i].piece_v_pawn_v + j)); + printf("%4s,", buf); + } + printf(" }, /* game phase (%i) */\n", i); + } + printf("};\n"); +} + +/* based on pseudo code from wiki */ +void local_optimize(FILE * epd) { + const int nParams = sizeof(tuned_values[0]) / sizeof(int); + float bestE = error(epd); + + int improved = 1; + int count = 0; + + while (improved) { + improved = 0; + + for (int i = 0; i < 4; ++i) { + /* keep the pawn value at 100, to define the scale in cps */ + for (int pi = 1; pi < nParams; pi++) { + + ((int*) &tuned_values[i])[pi] += 1; + + double newE = error(epd); + + if (newE < bestE) { + printf("error %f -> %f\n", bestE, newE); + bestE = newE; + improved = 1; + } else { + ((int*) &tuned_values[i])[pi] -= 2; + newE = error(epd); + if (newE < bestE) { + printf("error %f -> %f\n", bestE, newE); + bestE = newE; + improved = 1; + } else { + ((int*) &tuned_values[i])[pi] += 1; /* reset to old value */ + } + } + } + } + if (count++ % 1000) { + print_values(); + } + } +} + +int stopped = 0; +unsigned long long nodes; + +int main(int argc, const char * argv[]) +{ + FILE * epd; + + initialize_mat_tables(); + + if (argc != 2 || NULL == (epd = fopen(argv[1], "r"))) { + printf("Usage: %s epd_file\n", argv[0]); + return -1; + } + + local_optimize(epd); + + printf("new values:\n\n"); + print_values(); + + fclose(epd); + free(mat_table); + + return 0; +}