EOC databases now as open source

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

ed

EOC databases now as open source

Post by ed »

The ProDeo (Rebel) EOC database as open source. 5 minutes away easily building the biggest chess tree in the word and use it to improve your chess engine.

Add the following features to your chess engine or even your chess interface:

Use an EOC database as an opening book;
Use an EOC database to guide the search;
Use it as a (book/position) learning system;
Use it for display purposes in your GUI.

All info at: http://www.top-5000.nl/eoc.htm

Ed
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: EOC databases now as open source

Post by Michael Sherwin »

Hi Ed,

Life is strange at times. There are coincidences all the time that we do not know wether they were intentional or accidental. There are often confluinces that lead people down virtually the same path with out realizing it. This seems as though this could be one of those times. As, RomiChess has had these abilities for almost a year now, almost exactly as how you describe them. RomiChess remembers every game she plays and stores it in a giant tree with percentages similar to yours including a bonus/penalty system. This tree is used as an opening book, as a book learner, as a position learner, to guide the search and has had the ability to merge an external database of millions of games. It has been demonstrated on this board and at the Winboard forum numerous times and shown that with not that many learned games that it can even beat much stronger learning engines like Glaurung 1.2.1 with a 90% plus score when dealing with a limited number of starting positions. I even emailed all this to you about six months ago and suggested that you do something similar for Pro Deo. I even sent/or_mentioned_where_you_could_get the_source_code for RomiChess, but with no reply from you.

I believe in pure coincidences and I will tell you of another ironic coincidence. After I had first released RomiChess I read your paper on chess programming and noted that our approaches were very similar and now our programs are even more similar! :) Although RomiChess pales in comparison to Rebel and Pro Deo. :(

Since so many people here are aware of my work and undoubtably can see the simularity of our learning systems it might be a good idea for you to address the above noted coincidences. After all, I always said that anyone can use and improve upon my learning system and all that I asked is to be given some credit. However, if you arrived at the same destination with out knowledge of my work then people aught to hear it from you, so they will not believe that you cloned someone else work, with out acknowledement.

I do appreciate this contribution that you have made and am very interested in how it has been improved. I hope that many programmers find it very useful! :D

Mike
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Dann Corbit
Posts: 12541
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: EOC databases now as open source

Post by Dann Corbit »

Ed Schroder is the nicest guy in the world.

The only problem is that you have set the bar too high for the rest of us!
;-)
Tord Romstad
Posts: 1808
Joined: Wed Mar 08, 2006 9:19 pm
Location: Oslo, Norway

Re: EOC databases now as open source

Post by Tord Romstad »

Michael Sherwin wrote:It has been demonstrated on this board and at the Winboard forum numerous times and shown that with not that many learned games that it can even beat much stronger learning engines like Glaurung 1.2.1 with a 90% plus score when dealing with a limited number of starting positions.
Hello Michael,

Just a pedantic correction: Glaurung 1.2.1 is not a learning engine in any meaningful sense of the word. It is true that there is a UCI parameter named "Position learning", but all this feature does is to remember the results of the last few searches from the root and store them to a an array and a small binary file. If you play a computer vs computer match, the entire learning file will probably be overwritten multiple times before the same position occurs again on the board. As a consequence, the learning feature almost certainly has no effect whatsoever in engine vs engine games.

The only purpose of the learning feature in Glaurung is to make the program a better analysis tool. During interactive analysis session, when Glaurung wants to play a move which you know is bad, show it why it is bad (by playing out the relevant lines on the board while Glaurung runs in analysis mode) and back up to the position you started with, and Glaurung will (hopefully) understand why the move is bad.

Because hardly anyone uses Glaurung as an analysis tool (and I can't blame them; the program is far too speculative to be reliable for analysis) and because nobody understands the purpose of the learning function, I've decided not to include it in future versions.

Of course, what I write above is not intended as criticism of the excellent work you have done on RomiChess' learning function - your results are certainly very impressive. :)

Tord
ed

Re: EOC databases now as open source

Post by ed »

Hi Michael,

Nice to meet a brother in EOC. :lol: :lol: I am sorry, I do not remember an email of yours, most likely it became a target of my spam filter as I do have the intention to answer email.

I had the EOC idea already in the early 90's but then the availability of games was so little the system made no sense at all so I never activated the code. It remained that way till 1998 till the volume of available games was high enough to justify a commercial release, see: http://www.rebel.nl/rebel10e.htm

I have retired from the playing strength circus but of curiosity reasons only I definitely going to try the EOC comp-comp database and find out if 6.x million comp-comp positions bring any difference.

This is big fun.

Regards,

Ed

Michael Sherwin wrote:Hi Ed,

Life is strange at times. There are coincidences all the time that we do not know wether they were intentional or accidental. There are often confluinces that lead people down virtually the same path with out realizing it. This seems as though this could be one of those times. As, RomiChess has had these abilities for almost a year now, almost exactly as how you describe them. RomiChess remembers every game she plays and stores it in a giant tree with percentages similar to yours including a bonus/penalty system. This tree is used as an opening book, as a book learner, as a position learner, to guide the search and has had the ability to merge an external database of millions of games. It has been demonstrated on this board and at the Winboard forum numerous times and shown that with not that many learned games that it can even beat much stronger learning engines like Glaurung 1.2.1 with a 90% plus score when dealing with a limited number of starting positions. I even emailed all this to you about six months ago and suggested that you do something similar for Pro Deo. I even sent/or_mentioned_where_you_could_get the_source_code for RomiChess, but with no reply from you.

I believe in pure coincidences and I will tell you of another ironic coincidence. After I had first released RomiChess I read your paper on chess programming and noted that our approaches were very similar and now our programs are even more similar! :) Although RomiChess pales in comparison to Rebel and Pro Deo. :(

Since so many people here are aware of my work and undoubtably can see the simularity of our learning systems it might be a good idea for you to address the above noted coincidences. After all, I always said that anyone can use and improve upon my learning system and all that I asked is to be given some credit. However, if you arrived at the same destination with out knowledge of my work then people aught to hear it from you, so they will not believe that you cloned someone else work, with out acknowledement.

I do appreciate this contribution that you have made and am very interested in how it has been improved. I hope that many programmers find it very useful! :D

Mike
ed

Re: EOC databases now as open source

Post by ed »

Dann Corbit wrote:Ed Schroder is the nicest guy in the world.
The sentiment is mutual Dann, but I can assure Mrs. Schroder at times totally disagrees with you. :wink: :wink:

EPD regards,

Ed
Dann Corbit
Posts: 12541
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: EOC databases now as open source

Post by Dann Corbit »

Here is your code as a C++ class:

Code: Select all

/* EOC module for Chess Programs
   written by Ed Schr”der
   Version 1.00

   This information provides the way how to include the ProDeo EOC system
   into your chess engine.

   Include "eoc.c" into your project and compile.

   EXAMPLE.EOC    - Example demonstration EOC database. An EOC database is the
   statistic representation of a game collection (PGN or DAT),
   see: http://www.rebel.nl/r11-eoc.htm
   EOC databases can be easily made with ProDeo Tools. Get it
   at: http://www.top-5000.nl/prodeodos.htm

   Initialization - Call the routine "initialize_eoc()" once.

   Operation      - Create an EPD string from the position you want to find and
   strcpy it into the string "EPD", then call the routine
   "search_position_in_eoc" to search the EOC database.

   - When the position is found "amount" contains the number
   of games the position occurs and "percentage" contains
   the percentage of the position has scored. When the position
   is not found both variables contain -1.

   Possibilities  - Both variables provide enough information to allow you to add
   the following features to your chess engine or even your chess
   interface: 1) Use an EOC database as an opening book;
   2) Use an EOC database to guide the search;
   3) Use it as a (book/position) learning system;
   4) Use it for display purposes in your GUI.

   As openingbook - The basic idea: if a position occurs 20 times in the EOC
   database with a score of 60% it's safe to enter this position.
   Procedure: for every legal move call "search_position_in_eoc"
   and via "amount" and "percentage" decide if the move
   is a candidate book move. See also the demonstration code in
   the "main" section.

   As guide       - As an alternative you can use the EOC information as a tool to
   guide the search. Based on "amount" and "percentage"
   create a bonus/penalty score for each found EOC move and update
   the corresponding root move with that score. It's fully explained
   at: http://www.rebel.nl/r11-eoc.htm (section: alternative goals
   of EOC).

   As learner     - Just create an EOC database from the games your program has
   played with ProDeo Tools. Via "amount" and "percentage"
   decide which opening to avoid or to stimulate. When your engine
   has entered a position with a bad percentage consider to switch
   to a somewhat different playing style to avoid your engine to
   lose again.

   Display info   - Add a nice statitic to your chess interface, see example
   picture of an EOC database running under ChessPartner at:
   http://www.top-5000.nl/pics/eoc.jpg
   When a position is found 4 more other variables are filled:
   won   : games won
   lost  : games lost
   draw  : games ended in a draw
   total : total positions of the loaded EOC database.
   See the  demonstration code in the "main" section.

   EPD creation   - To create an EPD string from the current board position check
   chapter 16 from: http://www.tim-mann.org/Standard
   Castling status and en-passant information are not needed to
   include in the EPD string, the module only needs the current
   position and the colour to move.

   Remarks        - Realize that white moves usually score 5-7% better than black
   moves during the first moves. This is represented in the
   variables: "perc_white" and "perc_black" and pre-filled
   with 55% and 45% respectively as a base for calculation. See the
   demonstration code in the "main" section.

   Technical      - Short description of the EOC format:

   Each position is stored into 11 bytes and 2 separate files,
   1 for white and 1 for black (*.EOC and *.BAL)

   Byte 1-8 : 64 bit hashkey
   Byte 9   : number positions won by white
   Byte 10  : number positions won by black
   Byte 11  : number of draw positions

   Positions over 256 games are stored in 2 separate files, 1 for
   white and 1 for black (*.WBX and *.BBX). Same format as above
   only now with 32-bit counters. These are only few so a lot of
   disk-space and consistently processor time is saved.

   The 2 big EOC files (*.EOC and *.BAL) are controlled by 2 index
   files (*.WBI and *.BBI) for fast access.
   Copyright      - This file and its components although distributed as freeware in
   no way may become subject to any form of commerce. Permission
   must be asked first.

   - This file and its components come as is and can only be used as
   such. It's forbidden to change, add, delete any of its components
   and only can be distributed in original form.

   Questions      - For questions, suggestions, bug reports etc. contact me at the
   CCC forum: http://216.25.93.108/forum
   Ed Schr”der
   Deventer, May 2007
   matador@home.nl
   www.top-5000.nl

 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>

static const char BORDPOS&#91;&#93; =
&#123;
    8, 18, 28, 38, 48, 58, 68, 78,
    7, 17, 27, 37, 47, 57, 67, 77,
    6, 16, 26, 36, 46, 56, 66, 76,
    5, 15, 25, 35, 45, 55, 65, 75,
    4, 14, 24, 34, 44, 54, 64, 74,
    3, 13, 23, 33, 43, 53, 63, 73,
    2, 12, 22, 32, 42, 52, 62, 72,
    1, 11, 21, 31, 41, 51, 61, 71, 0
&#125;;

#define RBI_BITS         16     /* bits used index file */
#define RBI_MASK     0xffff     /* the corresponding bit mask */

#define WHITE 	          0
#define BLACK 	          1

class EOC &#123;

 private&#58;

    char            file&#91;FILENAME_MAX&#93;; /* full path goes here */
    char            EPD&#91;200&#93;;
    long            RANDOM1&#91;1120&#93;;
    long            RANDOM2&#91;1120&#93;;
    char            _BORD&#91;256&#93;;
    long            HK1,
                    HK2;
    char            ERROR;

    float           amount;
    float           percentage;
    int             won;
    int             loss;
    int             draw;
    int             total;
    int             perc_white;
    int             perc_black;
    int             minimum_games;
    char            message&#91;100&#93;;
    char            color;

 public&#58;

    EOC&#40;) &#123;
        char           *eoc_location;
        memset&#40;EPD, 0, sizeof EPD&#41;;
        memset&#40;RANDOM1, 0, sizeof RANDOM1&#41;;
        memset&#40;RANDOM2, 0, sizeof RANDOM2&#41;;
        memset&#40;_BORD, 0, sizeof _BORD&#41;;
        memset&#40;message, 0, sizeof message&#41;;
        HK1 = 0;
        HK2 = 0;
        ERROR = 0;
        color = WHITE;
        amount = percentage = 0.0;
        won = loss = draw = total = 0;
        perc_white = 55;
        perc_black = 45;
        minimum_games = 10;
        strcpy&#40;file, "eoc\\example.eoc");
        eoc_location = getenv&#40;"EOC_LOCATION");
        if &#40;eoc_location&#41; &#123;
            if &#40;strlen&#40;eoc_location&#41; < sizeof file&#41;
                strcpy&#40;file, eoc_location&#41;;
            else
                printf&#40;"EOC_LOCATION (%s&#41; is longer than the longest allowed file name on your system.");
        &#125;
        initialize_eoc&#40;);
    &#125;

    ~EOC&#40;) &#123;
        ;
    &#125;

	/* Private member inquiry methods */
    inline char    *get_file&#40;) &#123;
        return file;
    &#125;
    inline char    *get_EPD&#40;) &#123;
        return EPD;
    &#125;
    inline char    *get_BORD&#40;) &#123;
        return _BORD;
    &#125;
    inline long     get_HK1&#40;) &#123;
        return HK1;
    &#125;
    inline long     get_HK2&#40;) &#123;
        return HK2;
    &#125;
    inline char     get_ERROR&#40;) &#123;
        return ERROR;
    &#125;
    inline float    get_amount&#40;) &#123;
        return amount;
    &#125;
    inline float    get_percentage&#40;) &#123;
        return percentage;
    &#125;
    inline int      get_won&#40;) &#123;
        return won;
    &#125;
    inline int      get_loss&#40;) &#123;
        return loss;
    &#125;
    inline int      get_draw&#40;) &#123;
        return draw;
    &#125;
    inline int      get_total&#40;) &#123;
        return total;
    &#125;
    inline int      get_perc_white&#40;) &#123;
        return perc_white;
    &#125;
    inline int      get_perc_black&#40;) &#123;
        return perc_black;
    &#125;
    inline int      get_minimum_games&#40;) &#123;
        return minimum_games;
    &#125;
    inline char    *get_message&#40;) &#123;
        return message;
    &#125;
    inline char     get_color&#40;) &#123;
        return color;
    &#125;

	/* Private member modification methods */
    inline void     set_HK1&#40;long rhs&#41; &#123;
        HK1 = rhs;
    &#125;
    inline void     set_HK2&#40;long rhs&#41; &#123;
        HK2 = rhs;
    &#125;
    inline void     set_ERROR&#40;char rhs&#41; &#123;
        ERROR = rhs;
    &#125;
    inline void     set_amount&#40;float rhs&#41; &#123;
        amount = rhs;
    &#125;
    inline void     set_percentage&#40;float rhs&#41; &#123;
        percentage = rhs;
    &#125;
    inline void     set_won&#40;int rhs&#41; &#123;
        won = rhs;
    &#125;
    inline void     set_loss&#40;int rhs&#41; &#123;
        loss = rhs;
    &#125;
    inline void     set_draw&#40;int rhs&#41; &#123;
        draw = rhs;
    &#125;
    inline void     set_total&#40;int rhs&#41; &#123;
        total = rhs;
    &#125;
    inline void     set_perc_white&#40;int rhs&#41; &#123;
        perc_white = rhs;
    &#125;
    inline void     set_perc_black&#40;int rhs&#41; &#123;
        perc_black = rhs;
    &#125;
    inline void     set_minimum_games&#40;int rhs&#41; &#123;
        minimum_games = rhs;
    &#125;
    inline void     set_color&#40;char rhs&#41; &#123;
        color = rhs;
    &#125;
    inline void     set_message&#40;char *rhs&#41; &#123;
        strncpy&#40;message, rhs, sizeof message&#41;;
    &#125;
    inline void     set_file&#40;char *rhs&#41; &#123;
        strncpy&#40;file, rhs, sizeof file&#41;;
    &#125;
    inline void     set_EPD&#40;char *rhs&#41; &#123;
        strncpy&#40;EPD, rhs, sizeof EPD&#41;;
    &#125;
    inline void     set_BORD&#40;char *rhs&#41; &#123;
        strncpy&#40;_BORD, rhs, sizeof _BORD&#41;;
    &#125;
	/*
	Typical output for unit test method&#58;

	Get moves for start position

	Result for 1.e4 4067.000000% positions &#40;56.97%)
	Result for 1.d4 4756.000000% positions &#40;55.40%)
	Result for 1.c4 911.000000% positions &#40;54.12%)
	Press <Enter key> to continue


	Get moves after 1.e4

	Result for 1.e4 c5 1648.000000% positions &#40;45.39%)
	Result for 1.e4 e5 1249.000000% positions &#40;41.83%)
	Result for 1.e4 d6 128.000000% positions &#40;36.72%)
	Let's now decide which of the 3 above moves are good candidate book moves.
	Press <Enter key> to continue


	Result for 1.e4 c5 1648.000000% positions &#40;45.39%)
	play
	Result for 1.e4 e5 1249.000000% positions &#40;41.83%)
	play
	Result for 1.e4 d6 128.000000% positions &#40;36.72%)
	don't play

	Let's now create some statistics for the interface.
	Press <Enter key> to continue


	Move    Won   Draw   Loss Perc  Total

	c7c5    332    832    484 45.39%   1648
	e7e5    180    685    384 41.83%   1249
	d7d6     24     46     58 36.72%    128

	Tot     536   1563    926        3025

	Total positions in EOC database&#58; 431767
	*/
    inline int      unit_test&#40;int argc, char *argv&#91;&#93;) &#123;
        int             tot_won,
                        tot_draw,
                        tot_loss;
        char            string&#91;20&#93;;

        if &#40;ERROR&#41; &#123;
            printf&#40;"Something went wrong, error-code %d", ERROR&#41;;
            exit&#40;1&#41;;
        &#125;
/* */
/*      Get moves for start position */
/* */
        printf&#40;"\n\nGet moves for start position\n\n");

        strcpy&#40;EPD, "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq e3"); /* search for 1.e4 */
        search_position_in_eoc&#40;);
        if &#40;ERROR&#41;
            printf&#40;"Something went wrong, error-code %d", ERROR&#41;;
        printf&#40;"Result for 1.e4 %f%% positions (%.2f%%)\n", amount, percentage&#41;;

        strcpy&#40;EPD, "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR w KQkq d3"); /* search for 1.d4 */
        search_position_in_eoc&#40;);
        if &#40;ERROR&#41;
            printf&#40;"Something went wrong, error-code %d", ERROR&#41;;
        printf&#40;"Result for 1.d4 %f%% positions (%.2f%%)\n", amount, percentage&#41;;

        strcpy&#40;EPD, "rnbqkbnr/pppppppp/8/8/2P5/8/PP1PPPPP/RNBQKBNR w KQkq c3"); /* search for 1.c4 */
        search_position_in_eoc&#40;);
        if &#40;ERROR&#41;
            printf&#40;"Something went wrong, error-code %d", ERROR&#41;;
        printf&#40;"Result for 1.c4 %f%% positions (%.2f%%)\n", amount, percentage&#41;;
        printf&#40;"Press <Enter key> to continue ");
        fgets&#40;string, sizeof string, stdin&#41;;

/* */
/*      Get moves after 1.e4 */
/* */
        printf&#40;"\n\nGet moves after 1.e4\n\n");

        strcpy&#40;EPD, "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR b KQkq c6");       /* search for 1.e4 c5 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 c5 %f%% positions (%.2f%%)\n", amount, percentage&#41;;

        strcpy&#40;EPD, "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e6");       /* search for 1.e4 e5 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 e5 %f%% positions (%.2f%%)\n", amount, percentage&#41;;

        strcpy&#40;EPD, "rnbqkbnr/ppp1pppp/3p4/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq -");        /* search for 1.e4 d6 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 d6 %f%% positions (%.2f%%)\n", amount, percentage&#41;;

        printf&#40;"Let's now decide which of the 3 above moves are good candidate book moves.\n");
        printf&#40;"Press <Enter key> to continue ");
        fgets&#40;string, sizeof string, stdin&#41;;

/* */
/*      Check moves after 1.e4 */
/* */
        strcpy&#40;EPD, "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR b KQkq c6");       /* search for 1.e4 c5 */
        search_position_in_eoc&#40;);
        printf&#40;"\n\nResult for 1.e4 c5 %f%% positions (%.2f%%)\n", amount, percentage&#41;;
        to_play_or_not_to_play&#40;);
        printf&#40;"%s\n", message&#41;;

        strcpy&#40;EPD, "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e6");       /* search for 1.e4 e5 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 e5 %f%% positions (%.2f%%)\n", amount, percentage&#41;;
        to_play_or_not_to_play&#40;);
        printf&#40;"%s\n", message&#41;;

        strcpy&#40;EPD, "rnbqkbnr/ppp1pppp/3p4/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq -");        /* search for 1.e4 d6 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 d6 %f%% positions (%.2f%%)\n", amount, percentage&#41;;
        to_play_or_not_to_play&#40;);
        printf&#40;"%s\n\n", message&#41;;

        printf&#40;"Let's now create some statistics for the interface.\n");
        printf&#40;"Press <Enter key> to continue ");
        fgets&#40;string, sizeof string, stdin&#41;;

/* */
/*      Statistics */
/* */
        strcpy&#40;EPD, "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR b KQkq c6");       /* search for 1.e4 c5 */
        search_position_in_eoc&#40;);
        printf&#40;"\n\nMove    Won   Draw   Loss Perc  Total\n\n");
        printf&#40;"c7c5 %6d %6d %6d %.2f%% %6d\n", won, draw, loss, percentage, won + draw + loss&#41;;
        tot_won = won;
        tot_draw = draw;
        tot_loss = loss;

        strcpy&#40;EPD, "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e6");       /* search for 1.e4 e5 */
        search_position_in_eoc&#40;);
        printf&#40;"e7e5 %6d %6d %6d %.2f%% %6d\n", won, draw, loss, percentage, won + draw + loss&#41;;
        tot_won = tot_won + won;
        tot_draw = tot_draw + draw;
        tot_loss = tot_loss + loss;

        strcpy&#40;EPD, "rnbqkbnr/ppp1pppp/3p4/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq -");        /* search for 1.e4 d6 */
        search_position_in_eoc&#40;);
        printf&#40;"d7d6 %6d %6d %6d %.2f%% %6d\n", won, draw, loss, percentage, won + draw + loss&#41;;
        tot_won = tot_won + won;
        tot_draw = tot_draw + draw;
        tot_loss = tot_loss + loss;

        printf&#40;"\nTot  %6d %6d %6d      %6d\n\n", tot_won, tot_draw, tot_loss, tot_won + tot_draw + tot_loss&#41;;
        printf&#40;"Total positions in EOC database&#58; %d\n\n", total&#41;;
        return 0;
    &#125;

    inline void     to_play_or_not_to_play&#40;) &#123;
        int             mg,
                        perc;

        if &#40;color == WHITE&#41;
            perc = perc_white;  /* get percentage for color */
        else
            perc = perc_black;
        if &#40;amount > 25&#41;
            perc--;     /* allow 1% lower if more than  25
                                         * games are played */
        if &#40;amount > 50&#41;
            perc--;     /* allow 2% lower if more than  50
                                         * games are played */
        if &#40;amount > 100&#41;
            perc--;     /* allow 3% lower if more than 100
                                         * games are played */
        if &#40;amount > 500&#41;
            perc--;     /* allow 4% lower if more than 500
                                         * games are played */
        if &#40;percentage < perc&#41; &#123;
            printf&#40;"don't play");
            return;             /* don't play this move */
        &#125;
        mg = minimum_games;     /* check now for minimum
                                                 * games played */
        mg -= &#40;int&#41; &#40;percentage - perc&#41;;        /* decrease minimum games
                                                 * when high percentage */
        if &#40;amount < mg&#41; &#123;
            printf&#40;"don't play");
            return;             /* don't play this move */
        &#125;
        printf&#40;"play");
    &#125;

    inline void     initialize_eoc&#40;) &#123;  /* read hashkeys in memory */
        int             x,
                        y;
        char            s&#91;300&#93;;
        char           *q;
        FILE           *fp1;
        FILE           *fp2;

                        fp1 = fopen&#40;"random1.bin", "rb");
        if              &#40;fp1 == NULL&#41; &#123;
            fclose&#40;fp1&#41;;
            ERROR = 1;
            return;
        &#125;
        fp2 = fopen&#40;"random2.bin", "rb");
        if &#40;fp2 == NULL&#41; &#123;
            fclose&#40;fp2&#41;;
            ERROR = 1;
            return;
        &#125;
        for &#40;x = 0; x < 1120; x++) &#123;
            fread&#40;&RANDOM1&#91;x&#93;, 4, 1, fp1&#41;;
            fread&#40;&RANDOM2&#91;x&#93;, 4, 1, fp2&#41;;
        &#125;

        fclose&#40;fp1&#41;;
        fclose&#40;fp2&#41;;

        y = open&#40;file, O_RDONLY&#41;;
        x = filelength&#40;y&#41;;
        close&#40;y&#41;;               /* calculate total positions */
        total = x / 11;
        if (&#40;total * 11&#41; != x&#41; &#123;
            ERROR = 5;
            return;
        &#125;
        strcpy&#40;s, file&#41;;
        strlwr&#40;s&#41;;
        q = strstr&#40;s, ".eoc");
        if &#40;q == NULL&#41; &#123;
            ERROR = 6;
            return;
        &#125;                       /* wrong eoc filename */
        q&#91;1&#93; = 'b';
        q&#91;2&#93; = 'a';
        q&#91;3&#93; = 'l';             /* *.eoc to *.bal */

        y = open&#40;s, O_RDONLY&#41;;
        x = filelength&#40;y&#41;;
        close&#40;y&#41;;               /* get filelemgth &#40;black&#41; */
        y = &#40;x / 11&#41;;
        if (&#40;y * 11&#41; != x&#41; &#123;
            ERROR = 7;
            return;
        &#125;
        total = total + y;

        strcpy&#40;s, file&#41;;
        strlwr&#40;s&#41;;
        q = strstr&#40;s, ".eoc");
        q&#91;1&#93; = 'w';
        q&#91;2&#93; = 'b';
        q&#91;3&#93; = 'x';
        y = open&#40;s, O_RDONLY&#41;;
        x = filelength&#40;y&#41;;
        close&#40;y&#41;;
        y = x / 20;
        total = total + y;

        strcpy&#40;s, file&#41;;
        strlwr&#40;s&#41;;
        q = strstr&#40;s, ".eoc");
        q&#91;1&#93; = 'b';
        q&#91;2&#93; = 'b';
        q&#91;3&#93; = 'x';
        y = open&#40;s, O_RDONLY&#41;;
        x = filelength&#40;y&#41;;
        close&#40;y&#41;;
        y = x / 20;
        total = total + y;

    &#125;

    inline void     search_position_in_eoc&#40;) &#123;
        int             x,
                        y,
                        v;
        FILE           *fp3 = 0,
                       *fp4 = 0,
                       *fp5 = 0;
        unsigned long   rbi;
        long            hk1,
                        hk2;
        char           *q;
        float           f1,
                        f2,
                        f3,
                        f4,
                        f5,
                        f6;
        char            fn&#91;100&#93;;
        char            s&#91;100&#93;;
        char            ch;
        char            fentab&#91;&#93; = "??PNBRQKpnbrqk??";
        char            fenkleur&#91;&#93; = "wb??";

        amount = -1;
        percentage = -1;

/*      retrieve EPD */
/*      ============ */

        for &#40;x = 1; x <= 78; x++)
            if (_BORD&#91;x&#93; > 0&#41;
                _BORD&#91;x&#93; = 1;   /* empty board */

        x = -1;
        y = 0;
epd&#58;
        x++;
        ch = EPD&#91;x&#93;;
        if &#40;ch == '/')
            goto epd;
        if &#40;ch >= '1' && ch <= '8') &#123;
            v = ch - 48;
            y = y + v;
            goto test;
        &#125;
        for             &#40;v = 2; v <= 15; v++)
            if &#40;fentab&#91;v&#93; == ch&#41; &#123;
                _BORD&#91;BORDPOS&#91;y&#93;&#93; = v;
                y++;
                break;
            &#125;
        if &#40;v > 13&#41;
            goto error;
test&#58;   if &#40;y < 64&#41;
            goto epd;

        x++;
        if &#40;EPD&#91;x&#93; != ' ')
            goto error;

        x++;
        if &#40;EPD&#91;x&#93; == fenkleur&#91;0&#93;) &#123;
            color = 0;
            goto ready;
        &#125;                       /* white to move */
        if &#40;EPD&#91;x&#93; == fenkleur&#91;1&#93;) &#123;
            color = 1;
            goto ready;
        &#125;                       /* black to move */
error&#58;  ERROR = 2;
        return;
ready&#58;  strcpy&#40;s, file&#41;;
        strlwr&#40;s&#41;;
        q = strstr&#40;s, ".eoc");
        if &#40;q == NULL&#41; &#123;
            ERROR = 4;
            goto end;
        &#125;                       /* faulty eoc filename */
        q&#91;0&#93; = 0;               /* remove extension (.eoc") */

        if &#40;color == WHITE&#41; &#123;
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".eoc");
            fp3 = fopen&#40;fn, "rb");      /* 8-bit positions &#40;white&#41; */
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".wbi");
            fp4 = fopen&#40;fn, "rb");      /* index &#40;white&#41; */
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".wbx");
            fp5 = fopen&#40;fn, "rb");
        &#125;
        /* 32-bit positions &#40;white&#41; */
        else &#123;
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".bal");
            fp3 = fopen&#40;fn, "rb");      /* 8-bit positions &#40;black&#41; */
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".bbi");
            fp4 = fopen&#40;fn, "rb");      /* index &#40;black&#41; */
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".bbx");
            fp5 = fopen&#40;fn, "rb");
        &#125;                       /* 32-bit positions &#40;black&#41; */

        if &#40;fp3 == NULL&#41; &#123;
            ERROR = 3;
            goto end;
        &#125;                       /* eoc database not found */
        make_hashkey&#40;);

check&#58;  y = fread&#40;&hk1, 4, 1, fp5&#41;;
        /* check the 32 bit positions */
        if &#40;y < 1&#41;
            goto done;
        fread&#40;&hk2, 4, 1, fp5&#41;;
        fread&#40;&won, 4, 1, fp5&#41;;
        fread&#40;&loss, 4, 1, fp5&#41;;
        fread&#40;&draw, 4, 1, fp5&#41;;
        if &#40;hk1 == HK1 && hk2 == HK2&#41;
            goto found;         /* position found */
        goto check;

done&#58;   rbi = HK1 >> RBI_BITS;  /* get index */
        rbi = rbi & RBI_MASK;
        rbi = rbi << 2;
        fseek&#40;fp4, rbi, SEEK_SET&#41;;
        fread&#40;&rbi, 4, 1, fp4&#41;;
        fseek&#40;fp3, rbi, SEEK_SET&#41;;

next&#58;   y = fread&#40;&hk1, 4, 1, fp3&#41;;
        if &#40;y < 1&#41;
            goto end;
        fread&#40;&hk2, 4, 1, fp3&#41;;
        if &#40;hk1 > HK1&#41;
            goto end;
        if &#40;HK1 == hk1 && HK2 == hk2&#41; &#123;
            fread&#40;&won, 1, 1, fp3&#41;;
            won = won & 255;
            fread&#40;&loss, 1, 1, fp3&#41;;
            loss = loss & 255;
            fread&#40;&draw, 1, 1, fp3&#41;;
            draw = draw & 255;
            goto found;
        &#125;
        fread&#40;&s, 3, 1, fp3&#41;;   /* skip 3 bytes */
        goto next;

found&#58;  f1 = &#40;float&#41; won;
        f1 *= 2.0f;
        f2 = &#40;float&#41; draw;
        f4 = &#40;f1 + f2&#41; * 50.0f;
        f1 = &#40;float&#41; won;
        f3 = &#40;float&#41; loss;
        f5 = f1 + f2 + f3;
        f6 = f4 / f5;

        amount = f5;
        percentage = f6;

end&#58;    fclose&#40;fp3&#41;;
        fclose&#40;fp4&#41;;
        fclose&#40;fp5&#41;;

    &#125;

    inline void     make_hashkey&#40;) &#123;
        int             x,
                        y,
                        v,
                        sc;

        HK1 = 0;
        HK2 = 0;

        for             &#40;x = 1; x <= 78; x++) &#123;
            if (_BORD&#91;x&#93; < 2&#41;
                continue;
            sc = _BORD&#91;x&#93;;
            v = sc << 6;
            y = sc << 4;
            y = y + v;
            HK1 = HK1 ^ RANDOM1&#91;y + x&#93;;
            HK2 = HK2 ^ RANDOM2&#91;y + x&#93;;
        &#125;
    &#125;

&#125;;

/*          End of story */
int             main&#40;int argc, char **argv&#41;
&#123;
    EOC             EdsGroovyEncyclopedia;
    EdsGroovyEncyclopedia.unit_test&#40;argc, argv&#41;;
    return 0;
&#125;
Dann Corbit
Posts: 12541
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: EOC databases now as open source

Post by Dann Corbit »

Correction for percentages that were not supposed to be percentages:

Code: Select all

/* EOC module for Chess Programs
   written by Ed Schr”der
   Version 1.00

   This information provides the way how to include the ProDeo EOC system
   into your chess engine.

   Include "eoc.c" into your project and compile.

   EXAMPLE.EOC    - Example demonstration EOC database. An EOC database is the
   statistic representation of a game collection &#40;PGN or DAT&#41;,
   see&#58; http&#58;//www.rebel.nl/r11-eoc.htm
   EOC databases can be easily made with ProDeo Tools. Get it
   at&#58; http&#58;//www.top-5000.nl/prodeodos.htm

   Initialization - Call the routine "initialize_eoc&#40;)" once.

   Operation      - Create an EPD string from the position you want to find and
   strcpy it into the string "EPD", then call the routine
   "search_position_in_eoc" to search the EOC database.

   - When the position is found "amount" contains the number
   of games the position occurs and "percentage" contains
   the percentage of the position has scored. When the position
   is not found both variables contain -1.

   Possibilities  - Both variables provide enough information to allow you to add
   the following features to your chess engine or even your chess
   interface&#58; 1&#41; Use an EOC database as an opening book;
   2&#41; Use an EOC database to guide the search;
   3&#41; Use it as a &#40;book/position&#41; learning system;
   4&#41; Use it for display purposes in your GUI.

   As openingbook - The basic idea&#58; if a position occurs 20 times in the EOC
   database with a score of 60% it's safe to enter this position.
   Procedure&#58; for every legal move call "search_position_in_eoc"
   and via "amount" and "percentage" decide if the move
   is a candidate book move. See also the demonstration code in
   the "main" section.

   As guide       - As an alternative you can use the EOC information as a tool to
   guide the search. Based on "amount" and "percentage"
   create a bonus/penalty score for each found EOC move and update
   the corresponding root move with that score. It's fully explained
   at&#58; http&#58;//www.rebel.nl/r11-eoc.htm &#40;section&#58; alternative goals
   of EOC&#41;.

   As learner     - Just create an EOC database from the games your program has
   played with ProDeo Tools. Via "amount" and "percentage"
   decide which opening to avoid or to stimulate. When your engine
   has entered a position with a bad percentage consider to switch
   to a somewhat different playing style to avoid your engine to
   lose again.

   Display info   - Add a nice statitic to your chess interface, see example
   picture of an EOC database running under ChessPartner at&#58;
   http&#58;//www.top-5000.nl/pics/eoc.jpg
   When a position is found 4 more other variables are filled&#58;
   won   &#58; games won
   lost  &#58; games lost
   draw  &#58; games ended in a draw
   total &#58; total positions of the loaded EOC database.
   See the  demonstration code in the "main" section.

   EPD creation   - To create an EPD string from the current board position check
   chapter 16 from&#58; http&#58;//www.tim-mann.org/Standard
   Castling status and en-passant information are not needed to
   include in the EPD string, the module only needs the current
   position and the colour to move.

   Remarks        - Realize that white moves usually score 5-7% better than black
   moves during the first moves. This is represented in the
   variables&#58; "perc_white" and "perc_black" and pre-filled
   with 55% and 45% respectively as a base for calculation. See the
   demonstration code in the "main" section.

   Technical      - Short description of the EOC format&#58;

   Each position is stored into 11 bytes and 2 separate files,
   1 for white and 1 for black (*.EOC and *.BAL&#41;

   Byte 1-8 &#58; 64 bit hashkey
   Byte 9   &#58; number positions won by white
   Byte 10  &#58; number positions won by black
   Byte 11  &#58; number of draw positions

   Positions over 256 games are stored in 2 separate files, 1 for
   white and 1 for black (*.WBX and *.BBX&#41;. Same format as above
   only now with 32-bit counters. These are only few so a lot of
   disk-space and consistently processor time is saved.

   The 2 big EOC files (*.EOC and *.BAL&#41; are controlled by 2 index
   files (*.WBI and *.BBI&#41; for fast access.
   Copyright      - This file and its components although distributed as freeware in
   no way may become subject to any form of commerce. Permission
   must be asked first.

   - This file and its components come as is and can only be used as
   such. It's forbidden to change, add, delete any of its components
   and only can be distributed in original form.

   Questions      - For questions, suggestions, bug reports etc. contact me at the
   CCC forum&#58; http&#58;//216.25.93.108/forum
   Ed Schr”der
   Deventer, May 2007
   matador@home.nl
   www.top-5000.nl

 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>

static const char BORDPOS&#91;&#93; =
&#123;
    8, 18, 28, 38, 48, 58, 68, 78,
    7, 17, 27, 37, 47, 57, 67, 77,
    6, 16, 26, 36, 46, 56, 66, 76,
    5, 15, 25, 35, 45, 55, 65, 75,
    4, 14, 24, 34, 44, 54, 64, 74,
    3, 13, 23, 33, 43, 53, 63, 73,
    2, 12, 22, 32, 42, 52, 62, 72,
    1, 11, 21, 31, 41, 51, 61, 71, 0
&#125;;

#define RBI_BITS         16     /* bits used index file */
#define RBI_MASK     0xffff     /* the corresponding bit mask */

#define WHITE 	          0
#define BLACK 	          1

class EOC &#123;

 private&#58;

    char            file&#91;FILENAME_MAX&#93;; /* full path goes here */
    char            EPD&#91;200&#93;;
    long            RANDOM1&#91;1120&#93;;
    long            RANDOM2&#91;1120&#93;;
    char            _BORD&#91;256&#93;;
    long            HK1,
                    HK2;
    char            ERROR;

    float           amount;
    float           percentage;
    int             won;
    int             loss;
    int             draw;
    int             total;
    int             perc_white;
    int             perc_black;
    int             minimum_games;
    char            message&#91;100&#93;;
    char            color;

 public&#58;

    EOC&#40;) &#123;
        char           *eoc_location;
        memset&#40;EPD, 0, sizeof EPD&#41;;
        memset&#40;RANDOM1, 0, sizeof RANDOM1&#41;;
        memset&#40;RANDOM2, 0, sizeof RANDOM2&#41;;
        memset&#40;_BORD, 0, sizeof _BORD&#41;;
        memset&#40;message, 0, sizeof message&#41;;
        HK1 = 0;
        HK2 = 0;
        ERROR = 0;
        color = WHITE;
        amount = percentage = 0.0;
        won = loss = draw = total = 0;
        perc_white = 55;
        perc_black = 45;
        minimum_games = 10;
        strcpy&#40;file, "eoc\\example.eoc");
        eoc_location = getenv&#40;"EOC_LOCATION");
        if &#40;eoc_location&#41; &#123;
            if &#40;strlen&#40;eoc_location&#41; < sizeof file&#41;
                strcpy&#40;file, eoc_location&#41;;
            else
                printf&#40;"EOC_LOCATION (%s&#41; is longer than the longest allowed file name on your system.");
        &#125;
        initialize_eoc&#40;);
    &#125;

    ~EOC&#40;) &#123;
        ;
    &#125;

	/* Private member inquiry methods */
    inline char    *get_file&#40;) &#123;
        return file;
    &#125;
    inline char    *get_EPD&#40;) &#123;
        return EPD;
    &#125;
    inline char    *get_BORD&#40;) &#123;
        return _BORD;
    &#125;
    inline long     get_HK1&#40;) &#123;
        return HK1;
    &#125;
    inline long     get_HK2&#40;) &#123;
        return HK2;
    &#125;
    inline char     get_ERROR&#40;) &#123;
        return ERROR;
    &#125;
    inline float    get_amount&#40;) &#123;
        return amount;
    &#125;
    inline float    get_percentage&#40;) &#123;
        return percentage;
    &#125;
    inline int      get_won&#40;) &#123;
        return won;
    &#125;
    inline int      get_loss&#40;) &#123;
        return loss;
    &#125;
    inline int      get_draw&#40;) &#123;
        return draw;
    &#125;
    inline int      get_total&#40;) &#123;
        return total;
    &#125;
    inline int      get_perc_white&#40;) &#123;
        return perc_white;
    &#125;
    inline int      get_perc_black&#40;) &#123;
        return perc_black;
    &#125;
    inline int      get_minimum_games&#40;) &#123;
        return minimum_games;
    &#125;
    inline char    *get_message&#40;) &#123;
        return message;
    &#125;
    inline char     get_color&#40;) &#123;
        return color;
    &#125;

	/* Private member modification methods */
    inline void     set_HK1&#40;long rhs&#41; &#123;
        HK1 = rhs;
    &#125;
    inline void     set_HK2&#40;long rhs&#41; &#123;
        HK2 = rhs;
    &#125;
    inline void     set_ERROR&#40;char rhs&#41; &#123;
        ERROR = rhs;
    &#125;
    inline void     set_amount&#40;float rhs&#41; &#123;
        amount = rhs;
    &#125;
    inline void     set_percentage&#40;float rhs&#41; &#123;
        percentage = rhs;
    &#125;
    inline void     set_won&#40;int rhs&#41; &#123;
        won = rhs;
    &#125;
    inline void     set_loss&#40;int rhs&#41; &#123;
        loss = rhs;
    &#125;
    inline void     set_draw&#40;int rhs&#41; &#123;
        draw = rhs;
    &#125;
    inline void     set_total&#40;int rhs&#41; &#123;
        total = rhs;
    &#125;
    inline void     set_perc_white&#40;int rhs&#41; &#123;
        perc_white = rhs;
    &#125;
    inline void     set_perc_black&#40;int rhs&#41; &#123;
        perc_black = rhs;
    &#125;
    inline void     set_minimum_games&#40;int rhs&#41; &#123;
        minimum_games = rhs;
    &#125;
    inline void     set_color&#40;char rhs&#41; &#123;
        color = rhs;
    &#125;
    inline void     set_message&#40;char *rhs&#41; &#123;
        strncpy&#40;message, rhs, sizeof message&#41;;
    &#125;
    inline void     set_file&#40;char *rhs&#41; &#123;
        strncpy&#40;file, rhs, sizeof file&#41;;
    &#125;
    inline void     set_EPD&#40;char *rhs&#41; &#123;
        strncpy&#40;EPD, rhs, sizeof EPD&#41;;
    &#125;
    inline void     set_BORD&#40;char *rhs&#41; &#123;
        strncpy&#40;_BORD, rhs, sizeof _BORD&#41;;
    &#125;
	/*
	Typical output for unit test method&#58;

	Get moves for start position

	Result for 1.e4 4067 positions &#40;56.97%)
	Result for 1.d4 4756 positions &#40;55.40%)
	Result for 1.c4 911 positions &#40;54.12%)
	Press <Enter key> to continue


	Get moves after 1.e4

	Result for 1.e4 c5 1648 positions &#40;45.39%)
	Result for 1.e4 e5 1249 positions &#40;41.83%)
	Result for 1.e4 d6 128 positions &#40;36.72%)
	Let's now decide which of the 3 above moves are good candidate book moves.
	Press <Enter key> to continue


	Result for 1.e4 c5 1648 positions &#40;45.39%)
	play
	Result for 1.e4 e5 1249 positions &#40;41.83%)
	play
	Result for 1.e4 d6 128 positions &#40;36.72%)
	don't play

	Let's now create some statistics for the interface.
	Press <Enter key> to continue


	Move    Won   Draw   Loss Perc  Total

	c7c5    332    832    484 45.39%   1648
	e7e5    180    685    384 41.83%   1249
	d7d6     24     46     58 36.72%    128

	Tot     536   1563    926        3025

	Total positions in EOC database&#58; 431767

	*/
    inline int      unit_test&#40;int argc, char *argv&#91;&#93;) &#123;
        int             tot_won,
                        tot_draw,
                        tot_loss;
        char            string&#91;20&#93;;

        if &#40;ERROR&#41; &#123;
            printf&#40;"Something went wrong, error-code %d", ERROR&#41;;
            exit&#40;1&#41;;
        &#125;
/* */
/*      Get moves for start position */
/* */
        printf&#40;"\n\nGet moves for start position\n\n");

        strcpy&#40;EPD, "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq e3"); /* search for 1.e4 */
        search_position_in_eoc&#40;);
        if &#40;ERROR&#41;
            printf&#40;"Something went wrong, error-code %d", ERROR&#41;;
        printf&#40;"Result for 1.e4 %.0f positions (%.2f%%)\n", amount, percentage&#41;;

        strcpy&#40;EPD, "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR w KQkq d3"); /* search for 1.d4 */
        search_position_in_eoc&#40;);
        if &#40;ERROR&#41;
            printf&#40;"Something went wrong, error-code %d", ERROR&#41;;
        printf&#40;"Result for 1.d4 %.0f positions (%.2f%%)\n", amount, percentage&#41;;

        strcpy&#40;EPD, "rnbqkbnr/pppppppp/8/8/2P5/8/PP1PPPPP/RNBQKBNR w KQkq c3"); /* search for 1.c4 */
        search_position_in_eoc&#40;);
        if &#40;ERROR&#41;
            printf&#40;"Something went wrong, error-code %d", ERROR&#41;;
        printf&#40;"Result for 1.c4 %.0f positions (%.2f%%)\n", amount, percentage&#41;;
        printf&#40;"Press <Enter key> to continue ");
        fgets&#40;string, sizeof string, stdin&#41;;

/* */
/*      Get moves after 1.e4 */
/* */
        printf&#40;"\n\nGet moves after 1.e4\n\n");

        strcpy&#40;EPD, "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR b KQkq c6");       /* search for 1.e4 c5 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 c5 %.0f positions (%.2f%%)\n", amount, percentage&#41;;

        strcpy&#40;EPD, "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e6");       /* search for 1.e4 e5 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 e5 %.0f positions (%.2f%%)\n", amount, percentage&#41;;

        strcpy&#40;EPD, "rnbqkbnr/ppp1pppp/3p4/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq -");        /* search for 1.e4 d6 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 d6 %.0f positions (%.2f%%)\n", amount, percentage&#41;;

        printf&#40;"Let's now decide which of the 3 above moves are good candidate book moves.\n");
        printf&#40;"Press <Enter key> to continue ");
        fgets&#40;string, sizeof string, stdin&#41;;

/* */
/*      Check moves after 1.e4 */
/* */
        strcpy&#40;EPD, "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR b KQkq c6");       /* search for 1.e4 c5 */
        search_position_in_eoc&#40;);
        printf&#40;"\n\nResult for 1.e4 c5 %.0f positions (%.2f%%)\n", amount, percentage&#41;;
        to_play_or_not_to_play&#40;);
        printf&#40;"%s\n", message&#41;;

        strcpy&#40;EPD, "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e6");       /* search for 1.e4 e5 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 e5 %.0f positions (%.2f%%)\n", amount, percentage&#41;;
        to_play_or_not_to_play&#40;);
        printf&#40;"%s\n", message&#41;;

        strcpy&#40;EPD, "rnbqkbnr/ppp1pppp/3p4/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq -");        /* search for 1.e4 d6 */
        search_position_in_eoc&#40;);
        printf&#40;"Result for 1.e4 d6 %.0f positions (%.2f%%)\n", amount, percentage&#41;;
        to_play_or_not_to_play&#40;);
        printf&#40;"%s\n\n", message&#41;;

        printf&#40;"Let's now create some statistics for the interface.\n");
        printf&#40;"Press <Enter key> to continue ");
        fgets&#40;string, sizeof string, stdin&#41;;

/* */
/*      Statistics */
/* */
        strcpy&#40;EPD, "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR b KQkq c6");       /* search for 1.e4 c5 */
        search_position_in_eoc&#40;);
        printf&#40;"\n\nMove    Won   Draw   Loss Perc  Total\n\n");
        printf&#40;"c7c5 %6d %6d %6d %.2f%% %6d\n", won, draw, loss, percentage, won + draw + loss&#41;;
        tot_won = won;
        tot_draw = draw;
        tot_loss = loss;

        strcpy&#40;EPD, "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e6");       /* search for 1.e4 e5 */
        search_position_in_eoc&#40;);
        printf&#40;"e7e5 %6d %6d %6d %.2f%% %6d\n", won, draw, loss, percentage, won + draw + loss&#41;;
        tot_won = tot_won + won;
        tot_draw = tot_draw + draw;
        tot_loss = tot_loss + loss;

        strcpy&#40;EPD, "rnbqkbnr/ppp1pppp/3p4/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq -");        /* search for 1.e4 d6 */
        search_position_in_eoc&#40;);
        printf&#40;"d7d6 %6d %6d %6d %.2f%% %6d\n", won, draw, loss, percentage, won + draw + loss&#41;;
        tot_won = tot_won + won;
        tot_draw = tot_draw + draw;
        tot_loss = tot_loss + loss;

        printf&#40;"\nTot  %6d %6d %6d      %6d\n\n", tot_won, tot_draw, tot_loss, tot_won + tot_draw + tot_loss&#41;;
        printf&#40;"Total positions in EOC database&#58; %d\n\n", total&#41;;
        return 0;
    &#125;

    inline void     to_play_or_not_to_play&#40;) &#123;
        int             mg,
                        perc;

        if &#40;color == WHITE&#41;
            perc = perc_white;  /* get percentage for color */
        else
            perc = perc_black;
        if &#40;amount > 25&#41;
            perc--;     /* allow 1% lower if more than  25
                                         * games are played */
        if &#40;amount > 50&#41;
            perc--;     /* allow 2% lower if more than  50
                                         * games are played */
        if &#40;amount > 100&#41;
            perc--;     /* allow 3% lower if more than 100
                                         * games are played */
        if &#40;amount > 500&#41;
            perc--;     /* allow 4% lower if more than 500
                                         * games are played */
        if &#40;percentage < perc&#41; &#123;
            printf&#40;"don't play");
            return;             /* don't play this move */
        &#125;
        mg = minimum_games;     /* check now for minimum
                                                 * games played */
        mg -= &#40;int&#41; &#40;percentage - perc&#41;;        /* decrease minimum games
                                                 * when high percentage */
        if &#40;amount < mg&#41; &#123;
            printf&#40;"don't play");
            return;             /* don't play this move */
        &#125;
        printf&#40;"play");
    &#125;

    inline void     initialize_eoc&#40;) &#123;  /* read hashkeys in memory */
        int             x,
                        y;
        char            s&#91;300&#93;;
        char           *q;
        FILE           *fp1;
        FILE           *fp2;

                        fp1 = fopen&#40;"random1.bin", "rb");
        if              &#40;fp1 == NULL&#41; &#123;
            fclose&#40;fp1&#41;;
            ERROR = 1;
            return;
        &#125;
        fp2 = fopen&#40;"random2.bin", "rb");
        if &#40;fp2 == NULL&#41; &#123;
            fclose&#40;fp2&#41;;
            ERROR = 1;
            return;
        &#125;
        for &#40;x = 0; x < 1120; x++) &#123;
            fread&#40;&RANDOM1&#91;x&#93;, 4, 1, fp1&#41;;
            fread&#40;&RANDOM2&#91;x&#93;, 4, 1, fp2&#41;;
        &#125;

        fclose&#40;fp1&#41;;
        fclose&#40;fp2&#41;;

        y = open&#40;file, O_RDONLY&#41;;
        x = filelength&#40;y&#41;;
        close&#40;y&#41;;               /* calculate total positions */
        total = x / 11;
        if (&#40;total * 11&#41; != x&#41; &#123;
            ERROR = 5;
            return;
        &#125;
        strcpy&#40;s, file&#41;;
        strlwr&#40;s&#41;;
        q = strstr&#40;s, ".eoc");
        if &#40;q == NULL&#41; &#123;
            ERROR = 6;
            return;
        &#125;                       /* wrong eoc filename */
        q&#91;1&#93; = 'b';
        q&#91;2&#93; = 'a';
        q&#91;3&#93; = 'l';             /* *.eoc to *.bal */

        y = open&#40;s, O_RDONLY&#41;;
        x = filelength&#40;y&#41;;
        close&#40;y&#41;;               /* get filelemgth &#40;black&#41; */
        y = &#40;x / 11&#41;;
        if (&#40;y * 11&#41; != x&#41; &#123;
            ERROR = 7;
            return;
        &#125;
        total = total + y;

        strcpy&#40;s, file&#41;;
        strlwr&#40;s&#41;;
        q = strstr&#40;s, ".eoc");
        q&#91;1&#93; = 'w';
        q&#91;2&#93; = 'b';
        q&#91;3&#93; = 'x';
        y = open&#40;s, O_RDONLY&#41;;
        x = filelength&#40;y&#41;;
        close&#40;y&#41;;
        y = x / 20;
        total = total + y;

        strcpy&#40;s, file&#41;;
        strlwr&#40;s&#41;;
        q = strstr&#40;s, ".eoc");
        q&#91;1&#93; = 'b';
        q&#91;2&#93; = 'b';
        q&#91;3&#93; = 'x';
        y = open&#40;s, O_RDONLY&#41;;
        x = filelength&#40;y&#41;;
        close&#40;y&#41;;
        y = x / 20;
        total = total + y;

    &#125;

    inline void     search_position_in_eoc&#40;) &#123;
        int             x,
                        y,
                        v;
        FILE           *fp3 = 0,
                       *fp4 = 0,
                       *fp5 = 0;
        unsigned long   rbi;
        long            hk1,
                        hk2;
        char           *q;
        float           f1,
                        f2,
                        f3,
                        f4,
                        f5,
                        f6;
        char            fn&#91;100&#93;;
        char            s&#91;100&#93;;
        char            ch;
        char            fentab&#91;&#93; = "??PNBRQKpnbrqk??";
        char            fenkleur&#91;&#93; = "wb??";

        amount = -1;
        percentage = -1;

/*      retrieve EPD */
/*      ============ */

        for &#40;x = 1; x <= 78; x++)
            if (_BORD&#91;x&#93; > 0&#41;
                _BORD&#91;x&#93; = 1;   /* empty board */

        x = -1;
        y = 0;
epd&#58;
        x++;
        ch = EPD&#91;x&#93;;
        if &#40;ch == '/')
            goto epd;
        if &#40;ch >= '1' && ch <= '8') &#123;
            v = ch - 48;
            y = y + v;
            goto test;
        &#125;
        for             &#40;v = 2; v <= 15; v++)
            if &#40;fentab&#91;v&#93; == ch&#41; &#123;
                _BORD&#91;BORDPOS&#91;y&#93;&#93; = v;
                y++;
                break;
            &#125;
        if &#40;v > 13&#41;
            goto error;
test&#58;   if &#40;y < 64&#41;
            goto epd;

        x++;
        if &#40;EPD&#91;x&#93; != ' ')
            goto error;

        x++;
        if &#40;EPD&#91;x&#93; == fenkleur&#91;0&#93;) &#123;
            color = 0;
            goto ready;
        &#125;                       /* white to move */
        if &#40;EPD&#91;x&#93; == fenkleur&#91;1&#93;) &#123;
            color = 1;
            goto ready;
        &#125;                       /* black to move */
error&#58;  ERROR = 2;
        return;
ready&#58;  strcpy&#40;s, file&#41;;
        strlwr&#40;s&#41;;
        q = strstr&#40;s, ".eoc");
        if &#40;q == NULL&#41; &#123;
            ERROR = 4;
            goto end;
        &#125;                       /* faulty eoc filename */
        q&#91;0&#93; = 0;               /* remove extension (.eoc") */

        if &#40;color == WHITE&#41; &#123;
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".eoc");
            fp3 = fopen&#40;fn, "rb");      /* 8-bit positions &#40;white&#41; */
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".wbi");
            fp4 = fopen&#40;fn, "rb");      /* index &#40;white&#41; */
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".wbx");
            fp5 = fopen&#40;fn, "rb");
        &#125;
        /* 32-bit positions &#40;white&#41; */
        else &#123;
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".bal");
            fp3 = fopen&#40;fn, "rb");      /* 8-bit positions &#40;black&#41; */
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".bbi");
            fp4 = fopen&#40;fn, "rb");      /* index &#40;black&#41; */
            strcpy&#40;fn, s&#41;;
            strcat&#40;fn, ".bbx");
            fp5 = fopen&#40;fn, "rb");
        &#125;                       /* 32-bit positions &#40;black&#41; */

        if &#40;fp3 == NULL&#41; &#123;
            ERROR = 3;
            goto end;
        &#125;                       /* eoc database not found */
        make_hashkey&#40;);

check&#58;  y = fread&#40;&hk1, 4, 1, fp5&#41;;
        /* check the 32 bit positions */
        if &#40;y < 1&#41;
            goto done;
        fread&#40;&hk2, 4, 1, fp5&#41;;
        fread&#40;&won, 4, 1, fp5&#41;;
        fread&#40;&loss, 4, 1, fp5&#41;;
        fread&#40;&draw, 4, 1, fp5&#41;;
        if &#40;hk1 == HK1 && hk2 == HK2&#41;
            goto found;         /* position found */
        goto check;

done&#58;   rbi = HK1 >> RBI_BITS;  /* get index */
        rbi = rbi & RBI_MASK;
        rbi = rbi << 2;
        fseek&#40;fp4, rbi, SEEK_SET&#41;;
        fread&#40;&rbi, 4, 1, fp4&#41;;
        fseek&#40;fp3, rbi, SEEK_SET&#41;;

next&#58;   y = fread&#40;&hk1, 4, 1, fp3&#41;;
        if &#40;y < 1&#41;
            goto end;
        fread&#40;&hk2, 4, 1, fp3&#41;;
        if &#40;hk1 > HK1&#41;
            goto end;
        if &#40;HK1 == hk1 && HK2 == hk2&#41; &#123;
            fread&#40;&won, 1, 1, fp3&#41;;
            won = won & 255;
            fread&#40;&loss, 1, 1, fp3&#41;;
            loss = loss & 255;
            fread&#40;&draw, 1, 1, fp3&#41;;
            draw = draw & 255;
            goto found;
        &#125;
        fread&#40;&s, 3, 1, fp3&#41;;   /* skip 3 bytes */
        goto next;

found&#58;  f1 = &#40;float&#41; won;
        f1 *= 2.0f;
        f2 = &#40;float&#41; draw;
        f4 = &#40;f1 + f2&#41; * 50.0f;
        f1 = &#40;float&#41; won;
        f3 = &#40;float&#41; loss;
        f5 = f1 + f2 + f3;
        f6 = f4 / f5;

        amount = f5;
        percentage = f6;

end&#58;    fclose&#40;fp3&#41;;
        fclose&#40;fp4&#41;;
        fclose&#40;fp5&#41;;

    &#125;

    inline void     make_hashkey&#40;) &#123;
        int             x,
                        y,
                        v,
                        sc;

        HK1 = 0;
        HK2 = 0;

        for             &#40;x = 1; x <= 78; x++) &#123;
            if (_BORD&#91;x&#93; < 2&#41;
                continue;
            sc = _BORD&#91;x&#93;;
            v = sc << 6;
            y = sc << 4;
            y = y + v;
            HK1 = HK1 ^ RANDOM1&#91;y + x&#93;;
            HK2 = HK2 ^ RANDOM2&#91;y + x&#93;;
        &#125;
    &#125;

&#125;;

/*          End of story */
int             main&#40;int argc, char **argv&#41;
&#123;
    EOC             EdsGroovyEncyclopedia;
    EdsGroovyEncyclopedia.unit_test&#40;argc, argv&#41;;
    return 0;
&#125;
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: EOC databases now as open source

Post by Michael Sherwin »

Hi Ed,

Thanks for the clarification. We must think a lot alike, except your better at it! :)

Mike
ed wrote:Hi Michael,

Nice to meet a brother in EOC. :lol: :lol: I am sorry, I do not remember an email of yours, most likely it became a target of my spam filter as I do have the intention to answer email.

I had the EOC idea already in the early 90's but then the availability of games was so little the system made no sense at all so I never activated the code. It remained that way till 1998 till the volume of available games was high enough to justify a commercial release, see: http://www.rebel.nl/rebel10e.htm

I have retired from the playing strength circus but of curiosity reasons only I definitely going to try the EOC comp-comp database and find out if 6.x million comp-comp positions bring any difference.

This is big fun.

Regards,

Ed

If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: EOC databases now as open source

Post by Michael Sherwin »

Tord Romstad wrote:
Michael Sherwin wrote:It has been demonstrated on this board and at the Winboard forum numerous times and shown that with not that many learned games that it can even beat much stronger learning engines like Glaurung 1.2.1 with a 90% plus score when dealing with a limited number of starting positions.
Hello Michael,

Just a pedantic correction: Glaurung 1.2.1 is not a learning engine in any meaningful sense of the word. It is true that there is a UCI parameter named "Position learning", but all this feature does is to remember the results of the last few searches from the root and store them to a an array and a small binary file. If you play a computer vs computer match, the entire learning file will probably be overwritten multiple times before the same position occurs again on the board. As a consequence, the learning feature almost certainly has no effect whatsoever in engine vs engine games.

The only purpose of the learning feature in Glaurung is to make the program a better analysis tool. During interactive analysis session, when Glaurung wants to play a move which you know is bad, show it why it is bad (by playing out the relevant lines on the board while Glaurung runs in analysis mode) and back up to the position you started with, and Glaurung will (hopefully) understand why the move is bad.

Because hardly anyone uses Glaurung as an analysis tool (and I can't blame them; the program is far too speculative to be reliable for analysis) and because nobody understands the purpose of the learning function, I've decided not to include it in future versions.

Of course, what I write above is not intended as criticism of the excellent work you have done on RomiChess' learning function - your results are certainly very impressive. :)

Tord
Thanks Tord, for both the correction and especially the compliment about my learning system! That really makes me feel good that the author of such a strong engine such as Glaurung has noticed my work!! :D

Mike
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through