Simple open source program wanted

Discussion of chess software programming and technical issues.

Moderator: Ras

Pablo Vazquez
Posts: 154
Joined: Thu May 31, 2007 9:05 pm
Location: Madrid, Spain

Re: Simple open source program wanted

Post by Pablo Vazquez »

Dann Corbit wrote:
PK wrote:ok, had a spare couple of minutes for programming (and couldn't touch Glass because of heavy testing it is undergoing right now), so here comes a little addition to Dann's C++ code. now the little thing uses principal variation search.

www.koziol.home.pl/sungrous_mod.zip

and yes, it's a pleasure to modify this code, I wish I could write in such a simple manner.
At first blush, the PVS modification seems to be worth about 100 points.

We'll see how it stands in the morning

Code: Select all

   Program               Elo    +   -   Games   Score   Av.Op.  Draws
 1 Sungorus 64 bit pvs : 2574  193 182    13    65.4 %   2464   23.1 %
 2 Sungorus ja ANSI C  : 2467  164 168    14    42.9 %   2517   28.6 %
 3 Sungorus cpp 64     : 2462  179 185    13    42.3 %   2515   23.1 %
In 8000 40/2 games with cutechess-cli and Bob's positions I got like +10 vs plain alpha beta. With more games I think the difference should go down.
Dann Corbit
Posts: 12791
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: Simple open source program wanted

Post by Dann Corbit »

Pablo Vazquez wrote:
bhlangonijr wrote:
Dann Corbit wrote:
I made a C++ version of Sungorus that has no global variables.
Since the license is not clear, I won't post it on my site, but I did send a copy to the author.

Now main.cpp looks like this:

Code: Select all

#include "sungorus.h"

int main()
{
    sungorus s;
    s.UciLoop();
    return 0;
}
The nice thing about a C++ conversion is that all data objects are now class members so it should be much easier to make an SMP version.
Good stuff Dann! I just downloaded it for using in my personal tests. The thing I most like in it is having a very good playing strength without sacrifice the readability and simplicity of the code.
When I was first trying to learn chess programming, I took a look at Arasan's source code and thought: "My god, is it how a chess program must looks like?". Of course it is a good chess program, but the code is too complex for my taste. But then I found good stuffs like Sungorus, Scorpio, Glaurung, among others. :)
You can take a look at Olithink, it is smaller and stronger than my program, although some variable names are a bit cryptic.
I think if we added Olithink's mobility calculation to your program it will add another 100 Elo.
Dann Corbit
Posts: 12791
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: Simple open source program wanted

Post by Dann Corbit »

Pablo Vazquez wrote:
Dann Corbit wrote:
PK wrote:ok, had a spare couple of minutes for programming (and couldn't touch Glass because of heavy testing it is undergoing right now), so here comes a little addition to Dann's C++ code. now the little thing uses principal variation search.

www.koziol.home.pl/sungrous_mod.zip

and yes, it's a pleasure to modify this code, I wish I could write in such a simple manner.
At first blush, the PVS modification seems to be worth about 100 points.

We'll see how it stands in the morning

Code: Select all

   Program               Elo    +   -   Games   Score   Av.Op.  Draws
 1 Sungorus 64 bit pvs : 2574  193 182    13    65.4 %   2464   23.1 %
 2 Sungorus ja ANSI C  : 2467  164 168    14    42.9 %   2517   28.6 %
 3 Sungorus cpp 64     : 2462  179 185    13    42.3 %   2515   23.1 %
In 8000 40/2 games with cutechess-cli and Bob's positions I got like +10 vs plain alpha beta. With more games I think the difference should go down.
It did go down a little

Code: Select all

   Program                          Elo    +   -   Games   Score   Av.Op.  Draws

 1 Sungorus 64 bit pvs            : 2552   42  42   180    61.1 %   2474   34.4 %
 2 Sungorus cpp 64                : 2484   41  42   181    46.7 %   2507   33.7 %
 3 Sungorus ja ANSI C             : 2464   46  46   181    42.3 %   2518   20.4 %
Dann Corbit
Posts: 12791
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: Simple open source program wanted

Post by Dann Corbit »

Pablo Vazquez wrote:
PK wrote:ok, had a spare couple of minutes for programming (and couldn't touch Glass because of heavy testing it is undergoing right now), so here comes a little addition to Dann's C++ code. now the little thing uses principal variation search.

www.koziol.home.pl/sungrous_mod.zip

and yes, it's a pleasure to modify this code, I wish I could write in such a simple manner.
Thanks Pawel. I've been using PVS for some time in the development version with some positive effect, although I implemented it a bit differently. I will try your way.
I think that changing promotions to this order may be useful:

*list++ = (Q_PROM << 12) | (to << 6) | (to - 9);
*list++ = (N_PROM << 12) | (to << 6) | (to - 9);
*list++ = (R_PROM << 12) | (to << 6) | (to - 9);
*list++ = (B_PROM << 12) | (to << 6) | (to - 9);

You have knight promotion last. But when queen promotion is not wanted, the knight underpromotion is far more likely to be a good move than bishop or rook underpromotion. This will generate the moves in order of usefulness. For instance, the same change made a significant improvment for gnuchess.
Dann Corbit
Posts: 12791
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: Simple open source program wanted

Post by Dann Corbit »

Dann Corbit wrote:
Pablo Vazquez wrote:
PK wrote:ok, had a spare couple of minutes for programming (and couldn't touch Glass because of heavy testing it is undergoing right now), so here comes a little addition to Dann's C++ code. now the little thing uses principal variation search.

www.koziol.home.pl/sungrous_mod.zip

and yes, it's a pleasure to modify this code, I wish I could write in such a simple manner.
Thanks Pawel. I've been using PVS for some time in the development version with some positive effect, although I implemented it a bit differently. I will try your way.
I think that changing promotions to this order may be useful:

*list++ = (Q_PROM << 12) | (to << 6) | (to - 9);
*list++ = (N_PROM << 12) | (to << 6) | (to - 9);
*list++ = (R_PROM << 12) | (to << 6) | (to - 9);
*list++ = (B_PROM << 12) | (to << 6) | (to - 9);

You have knight promotion last. But when queen promotion is not wanted, the knight underpromotion is far more likely to be a good move than bishop or rook underpromotion. This will generate the moves in order of usefulness. For instance, the same change made a significant improvment for gnuchess.
I also thought a PST calculation like this might be better:

Code: Select all

#include "sungorus.h"

static const int  pstPawnO[8][8] = {
    180, 184, 186, 187, 187, 186, 184, 180,
    8,  18,  22,  27,  27,  22,  18,   8,
    -6,   2,   8,  20,  20,   8,   2,  -6,
    -8,   0,   7,  21,  21,   7,   0,  -8,
    -8,   1,   8,  18,  18,   8,   1,  -8,
    -3,   5,  11,  15,  15,  11,   5,  -3,
    3,  12,  16,  14,  14,  16,  12,   3,
    0,   0,   0,   0,   0,   0,   0,   0,
};

static const int  pstKnightO[8][8] = {
    -75, -42, -23, -15, -15, -23, -42, -75,
    -33, -10,   4,  10,  10,   4, -10, -33,
    -12,   7,  21,  27,  27,  21,   7, -12,
    -2,  16,  30,  37,  37,  30,  16,  -2,
    0,  18,  32,  40,  40,  32,  18,   0,
    0,  13,  30,  35,  35,  30,  13,   0,
    -21,  -4,   9,  14,  14,   9,  -4, -21,
    -108, -30, -14,  -9,  -9, -14, -30, -108,
};

static const int  pstBishopO[8][8] = {
    -9, -10,  -9,  -7,  -7,  -9, -10,  -9,
    -14,   7,   4,   6,   6,   4,   7, -14,
    0,   4,  13,  10,  10,  13,   4,   0,
    -1,   6,  10,  19,  19,  10,   6,  -1,
    -1,   6,  10,  19,  19,  10,   6,  -1,
    -2,   4,  12,   9,   9,  12,   4,  -2,
    -4,   7,   4,   6,   6,   4,   7,  -4,
    -8,  -9,  -7,  -4,  -4,  -7,  -9,  -8,
};

static const int  pstRookO[8][8] = {
    -3,   0,   2,   5,   5,   2,   0,  -3,
    -3,   0,   2,   5,   5,   2,   0,  -3,
    -5,  -2,   0,   3,   3,   0,  -2,  -5,
    -5,  -2,   0,   3,   3,   0,  -2,  -5,
    -5,  -2,   0,   3,   3,   0,  -2,  -5,
    -6,  -3,   0,   2,   2,   0,  -3,  -6,
    -6,  -3,   0,   2,   2,   0,  -3,  -6,
    -6,  -3,   1,   4,   4,   1,  -3,  -6,
};

static const int  pstQueenO[8][8] = {
    0,   1,   2,   3,   3,   2,   1,   0,
    -7,   7,   9,  10,  10,   9,   7,  -7,
    4,   7,   9,  10,  10,   9,   7,   4,
    3,   8,  10,  13,  13,  10,   8,   3,
    3,   8,  10,  13,  13,  10,   8,   3,
    2,   7,   8,   9,   9,   8,   7,   2,
    0,   5,   7,   8,   8,   7,   5,   0,
    -4,  -2,   1,   4,   4,   1,  -2,  -4,
};

static const int  pstKingO[8][8] = {
    68,  76,  49,  23,  23,  49,  76,  68,
    63,  72,  45,  18,  18,  45,  72,  63,
    50,  59,  32,   5,   5,  32,  59,  50,
    43,  51,  25,  -1,  -1,  25,  51,  43,
    41,  49,  22,  -4,  -4,  22,  49,  41,
    41,  49,  23,  -1,  -1,  23,  49,  41,
    46,  57,  25,   1,   1,  25,  57,  46,
    42,  56,  23,  -3,  -3,  23,  56,  42,
};

static const int  pstPawnE[8][8] = {
    2,   0,   0,   0,   0,   0,   0,   2,
    2,   0,  -2,  -3,  -3,  -2,   0,   2,
    1,  -1,  -2,  -4,  -4,  -2,  -1,   1,
    0,  -2,  -4,  -6,  -6,  -4,  -2,   0,
    -3,  -5,  -7,  -9,  -9,  -7,  -5,  -3,
    -7, -10, -12, -13, -13, -12, -10,  -7,
    -13, -15, -17, -19, -19, -17, -15, -13,
    -10, -12, -13, -14, -14, -13, -12, -10,
};

static const int  pstKnightE[8][8] = {
    -43, -31, -20, -14, -14, -20, -31, -43,
    -31, -19,  -7,  -1,  -1,  -7, -19, -31,
    -19,  -7,   3,   8,   8,   3,  -7, -19,
    -14,  -3,   7,  14,  14,   7,  -3, -14,
    -15,  -3,   6,  13,  13,   6,  -3, -15,
    -22, -10,   1,   6,   6,   1, -10, -22,
    -33, -21, -10,  -4,  -4, -10, -21, -33,
    -45, -34, -22, -16, -16, -22, -34, -45,
};

static const int  pstBishopE[8][8] = {
    -23, -16, -13,  -9,  -9, -13, -16, -23,
    -16,  -8,  -5,  -2,  -2,  -5,  -8, -16,
    -13,  -5,  -1,   1,   1,  -1,  -5, -13,
    -9,  -2,   1,   5,   5,   1,  -2,  -9,
    -9,  -2,   1,   5,   5,   1,  -2,  -9,
    -13,  -5,  -1,   1,   1,  -1,  -5, -13,
    -16,  -8,  -5,  -2,  -2,  -5,  -8, -16,
    -23, -16, -13,  -9,  -9, -13, -16, -23,
};

static const int  pstRookE[8][8] = {
    0,   0,   0,   0,   0,   0,   0,   0,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
};

static const int  pstQueenE[8][8] = {
    -35, -23, -17, -11, -11, -17, -23, -35,
    -23, -11,  -5,   0,   0,  -5, -11, -23,
    -17,  -5,   0,   6,   6,   0,  -5, -17,
    -11,   0,   6,  12,  12,   6,   0, -11,
    -11,   0,   6,  12,  12,   6,   0, -11,
    -17,  -5,   0,   6,   6,   0,  -5, -17,
    -23, -11,  -5,   0,   0,  -5, -11, -23,
    -35, -23, -17, -11, -11, -17, -23, -35,
};

static const int  pstKingE[8][8] = {
    -21,   6,  21,  33,  33,  21,   6, -21,
    5,  34,  49,  62,  62,  49,  34,   5,
    20,  48,  66,  80,  80,  66,  48,  20,
    35,  64,  82,  99,  99,  82,  64,  35,
    34,  63,  81,  97,  97,  81,  63,  34,
    19,  47,  64,  79,  79,  64,  47,  19,
    4,  32,  48,  61,  61,  48,  32,   4,
    -26,   1,  16,  28,  28,  16,   1, -26,
};
/*
enum colors {WC, BC, NO_CL};
enum chessmen {P, N, B, R, Q, K, NO_TP};
enum files {FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H};
enum ranks {RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8};
*/
int  sungorus::InterpolatePST(enum ranks rank, enum files file, enum colors color, int phase, enum chessmen chessman)
{
    int irank = (int) rank;

    if (color == BC) irank = 7 - irank;

    switch (chessman)
    {
    case  P:
        return pstPawnO[rank][file] * (7-phase)/8
               +
               pstPawnE[rank][file] * (phase)/8;
        break;
    case  N:
        return pstKnightO[rank][file] * (7-phase)/8
               +
               pstKnightE[rank][file] * (phase)/8;
        break;
    case  B:
        return pstBishopO[rank][file] * (7-phase)/8
               +
               pstBishopE[rank][file] * (phase)/8;
        break;
    case  R:
        return pstRookO[rank][file] * (7-phase)/8
               +
               pstRookE[rank][file] * (phase)/8;
        break;
    case  Q:
        return pstQueenO[rank][file] * (7-phase)/8
               +
               pstQueenE[rank][file] * (phase)/8;
        break;
    case  K:
        return pstKingO[rank][file] * (7-phase)/8
               +
               pstKingE[rank][file] * (phase)/8;
        break;

    }
}
Pablo Vazquez
Posts: 154
Joined: Thu May 31, 2007 9:05 pm
Location: Madrid, Spain

Re: Simple open source program wanted

Post by Pablo Vazquez »

Dann Corbit wrote:
Dann Corbit wrote:
Pablo Vazquez wrote:
PK wrote:ok, had a spare couple of minutes for programming (and couldn't touch Glass because of heavy testing it is undergoing right now), so here comes a little addition to Dann's C++ code. now the little thing uses principal variation search.

www.koziol.home.pl/sungrous_mod.zip

and yes, it's a pleasure to modify this code, I wish I could write in such a simple manner.
Thanks Pawel. I've been using PVS for some time in the development version with some positive effect, although I implemented it a bit differently. I will try your way.
I think that changing promotions to this order may be useful:

*list++ = (Q_PROM << 12) | (to << 6) | (to - 9);
*list++ = (N_PROM << 12) | (to << 6) | (to - 9);
*list++ = (R_PROM << 12) | (to << 6) | (to - 9);
*list++ = (B_PROM << 12) | (to << 6) | (to - 9);

You have knight promotion last. But when queen promotion is not wanted, the knight underpromotion is far more likely to be a good move than bishop or rook underpromotion. This will generate the moves in order of usefulness. For instance, the same change made a significant improvment for gnuchess.
I also thought a PST calculation like this might be better:

Code: Select all

#include "sungorus.h"

static const int  pstPawnO[8][8] = {
    180, 184, 186, 187, 187, 186, 184, 180,
    8,  18,  22,  27,  27,  22,  18,   8,
    -6,   2,   8,  20,  20,   8,   2,  -6,
    -8,   0,   7,  21,  21,   7,   0,  -8,
    -8,   1,   8,  18,  18,   8,   1,  -8,
    -3,   5,  11,  15,  15,  11,   5,  -3,
    3,  12,  16,  14,  14,  16,  12,   3,
    0,   0,   0,   0,   0,   0,   0,   0,
};

static const int  pstKnightO[8][8] = {
    -75, -42, -23, -15, -15, -23, -42, -75,
    -33, -10,   4,  10,  10,   4, -10, -33,
    -12,   7,  21,  27,  27,  21,   7, -12,
    -2,  16,  30,  37,  37,  30,  16,  -2,
    0,  18,  32,  40,  40,  32,  18,   0,
    0,  13,  30,  35,  35,  30,  13,   0,
    -21,  -4,   9,  14,  14,   9,  -4, -21,
    -108, -30, -14,  -9,  -9, -14, -30, -108,
};

static const int  pstBishopO[8][8] = {
    -9, -10,  -9,  -7,  -7,  -9, -10,  -9,
    -14,   7,   4,   6,   6,   4,   7, -14,
    0,   4,  13,  10,  10,  13,   4,   0,
    -1,   6,  10,  19,  19,  10,   6,  -1,
    -1,   6,  10,  19,  19,  10,   6,  -1,
    -2,   4,  12,   9,   9,  12,   4,  -2,
    -4,   7,   4,   6,   6,   4,   7,  -4,
    -8,  -9,  -7,  -4,  -4,  -7,  -9,  -8,
};

static const int  pstRookO[8][8] = {
    -3,   0,   2,   5,   5,   2,   0,  -3,
    -3,   0,   2,   5,   5,   2,   0,  -3,
    -5,  -2,   0,   3,   3,   0,  -2,  -5,
    -5,  -2,   0,   3,   3,   0,  -2,  -5,
    -5,  -2,   0,   3,   3,   0,  -2,  -5,
    -6,  -3,   0,   2,   2,   0,  -3,  -6,
    -6,  -3,   0,   2,   2,   0,  -3,  -6,
    -6,  -3,   1,   4,   4,   1,  -3,  -6,
};

static const int  pstQueenO[8][8] = {
    0,   1,   2,   3,   3,   2,   1,   0,
    -7,   7,   9,  10,  10,   9,   7,  -7,
    4,   7,   9,  10,  10,   9,   7,   4,
    3,   8,  10,  13,  13,  10,   8,   3,
    3,   8,  10,  13,  13,  10,   8,   3,
    2,   7,   8,   9,   9,   8,   7,   2,
    0,   5,   7,   8,   8,   7,   5,   0,
    -4,  -2,   1,   4,   4,   1,  -2,  -4,
};

static const int  pstKingO[8][8] = {
    68,  76,  49,  23,  23,  49,  76,  68,
    63,  72,  45,  18,  18,  45,  72,  63,
    50,  59,  32,   5,   5,  32,  59,  50,
    43,  51,  25,  -1,  -1,  25,  51,  43,
    41,  49,  22,  -4,  -4,  22,  49,  41,
    41,  49,  23,  -1,  -1,  23,  49,  41,
    46,  57,  25,   1,   1,  25,  57,  46,
    42,  56,  23,  -3,  -3,  23,  56,  42,
};

static const int  pstPawnE[8][8] = {
    2,   0,   0,   0,   0,   0,   0,   2,
    2,   0,  -2,  -3,  -3,  -2,   0,   2,
    1,  -1,  -2,  -4,  -4,  -2,  -1,   1,
    0,  -2,  -4,  -6,  -6,  -4,  -2,   0,
    -3,  -5,  -7,  -9,  -9,  -7,  -5,  -3,
    -7, -10, -12, -13, -13, -12, -10,  -7,
    -13, -15, -17, -19, -19, -17, -15, -13,
    -10, -12, -13, -14, -14, -13, -12, -10,
};

static const int  pstKnightE[8][8] = {
    -43, -31, -20, -14, -14, -20, -31, -43,
    -31, -19,  -7,  -1,  -1,  -7, -19, -31,
    -19,  -7,   3,   8,   8,   3,  -7, -19,
    -14,  -3,   7,  14,  14,   7,  -3, -14,
    -15,  -3,   6,  13,  13,   6,  -3, -15,
    -22, -10,   1,   6,   6,   1, -10, -22,
    -33, -21, -10,  -4,  -4, -10, -21, -33,
    -45, -34, -22, -16, -16, -22, -34, -45,
};

static const int  pstBishopE[8][8] = {
    -23, -16, -13,  -9,  -9, -13, -16, -23,
    -16,  -8,  -5,  -2,  -2,  -5,  -8, -16,
    -13,  -5,  -1,   1,   1,  -1,  -5, -13,
    -9,  -2,   1,   5,   5,   1,  -2,  -9,
    -9,  -2,   1,   5,   5,   1,  -2,  -9,
    -13,  -5,  -1,   1,   1,  -1,  -5, -13,
    -16,  -8,  -5,  -2,  -2,  -5,  -8, -16,
    -23, -16, -13,  -9,  -9, -13, -16, -23,
};

static const int  pstRookE[8][8] = {
    0,   0,   0,   0,   0,   0,   0,   0,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   1,   1,   1,   1,   1,
};

static const int  pstQueenE[8][8] = {
    -35, -23, -17, -11, -11, -17, -23, -35,
    -23, -11,  -5,   0,   0,  -5, -11, -23,
    -17,  -5,   0,   6,   6,   0,  -5, -17,
    -11,   0,   6,  12,  12,   6,   0, -11,
    -11,   0,   6,  12,  12,   6,   0, -11,
    -17,  -5,   0,   6,   6,   0,  -5, -17,
    -23, -11,  -5,   0,   0,  -5, -11, -23,
    -35, -23, -17, -11, -11, -17, -23, -35,
};

static const int  pstKingE[8][8] = {
    -21,   6,  21,  33,  33,  21,   6, -21,
    5,  34,  49,  62,  62,  49,  34,   5,
    20,  48,  66,  80,  80,  66,  48,  20,
    35,  64,  82,  99,  99,  82,  64,  35,
    34,  63,  81,  97,  97,  81,  63,  34,
    19,  47,  64,  79,  79,  64,  47,  19,
    4,  32,  48,  61,  61,  48,  32,   4,
    -26,   1,  16,  28,  28,  16,   1, -26,
};
/*
enum colors {WC, BC, NO_CL};
enum chessmen {P, N, B, R, Q, K, NO_TP};
enum files {FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H};
enum ranks {RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8};
*/
int  sungorus::InterpolatePST(enum ranks rank, enum files file, enum colors color, int phase, enum chessmen chessman)
{
    int irank = (int) rank;

    if (color == BC) irank = 7 - irank;

    switch (chessman)
    {
    case  P:
        return pstPawnO[rank][file] * (7-phase)/8
               +
               pstPawnE[rank][file] * (phase)/8;
        break;
    case  N:
        return pstKnightO[rank][file] * (7-phase)/8
               +
               pstKnightE[rank][file] * (phase)/8;
        break;
    case  B:
        return pstBishopO[rank][file] * (7-phase)/8
               +
               pstBishopE[rank][file] * (phase)/8;
        break;
    case  R:
        return pstRookO[rank][file] * (7-phase)/8
               +
               pstRookE[rank][file] * (phase)/8;
        break;
    case  Q:
        return pstQueenO[rank][file] * (7-phase)/8
               +
               pstQueenE[rank][file] * (phase)/8;
        break;
    case  K:
        return pstKingO[rank][file] * (7-phase)/8
               +
               pstKingE[rank][file] * (phase)/8;
        break;

    }
}
Thanks Dann, I will try your ideas. It's true that there is a lot of room for improvement in the evaluation.