Beginner programmer Winboard and chess computing advice

Discussions about Winboard/Xboard. News about engines or programs to use with these GUIs (e.g. tournament managers or adapters) belong in this sub forum.

Moderator: Andres Valverde

Beginner programmer Winboard and chess computing advice

Postby tr2 » 09 Jun 2009, 22:09

Hi

I am very much a novice & hobby programmer who enjoys all aspects of chess computing (engines / gui / pgn parsing etc etc) and I would like to know if I can get help & advice here on the forum on Winboard engine code and on other chess computing matters.

Currently I am looking at writing a very basic engine just as an introduction to programming & chess computing. Advanced techniques are way beyond me presently!
Presently I am putting together my own engine code after looking at many open source engines with code (currently I am at move generation with this project). Alongside this at the moment I am looking at 2 open source engines FirstChess & TSCP to learn from and I am trying to add winboard support to FirstChess (C). I have looked at the winboard protocol documentation but I am finding it tough to implement in FirstChess! (I have tried to use TSCP to guide me with this).

Has anyone here any experience with adding WB support for FirstChess or would anyone be prepared and able to help me do this? Is there any archived posts/resources on the forum here that would help for this?
Anyway I am grateful for some suggestions and any offer of help,and look forward to enjoying learning more at this forum
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby Dann Corbit » 10 Jun 2009, 05:48

TSCP is not so easy to learn from. I think that other programs are better for that purpose (though many have successfully learned from TSCP). It's a little tangled, uses lots of global variables, and has lots of very inefficient things in it.

For instance, I think that this is better:
http://www.3dkingdoms.com/chess/sam/samchess.html
Or this:
http://cap.connx.com/chess-engines/new- ... chess26a.c

If you understand bit twiddling, you might enjoy this (if -- for instance, things like xor and shifts are second nature to you):
http://home.arcor.de/dreamlike/chess/index.html

The minimal chess program (this one does not play with Winboard) is this thing:
http://www.geocities.com/axchess/firstchess.html

Some other must sees that are a bit more advanced:
Glaurung
Viper (a subset of Glaurung that shows how to do SMP programming)
Scorpion
Dann Corbit
 

Re: Beginner programmer Winboard and chess computing advice

Postby Dann Corbit » 10 Jun 2009, 07:03

Perhaps something along these lines could be useful for a start:
Code: Select all
/*
   FirstChess - Freeware, by Pham Hong Nguyen
   Version: beta
 */
/*
   * BASIC PARTS:                          *
   * Some definitions                      *
   * Board representation and main varians *
   * Move generator                        *
   * Evaluation for current position       *
   * Make and Take back a move, IsInCheck  *
   * Search function - a typical alphabeta *
   * Utility                               *
   * Main program                          *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define TIMEALLOC (55000)

typedef enum mybool {
false = 0, true = 1} mybool;
/*
   ****************************************************************************
   * Some definitions                                                         *
   ****************************************************************************
 */
#define   PAWN    0
#define   KNIGHT  1
#define   BISHOP  2
#define   ROOK    3
#define   QUEEN   4
#define   KING    5
#define   EMPTY   6
#define   WHITE   0
#define   BLACK   1

#define   VALUE_PAWN      100
#define   VALUE_KNIGHT    300
#define   VALUE_BISHOP    300
#define   VALUE_ROOK      500
#define   VALUE_QUEEN     900
#define   VALUE_KING      10000

#define   MATE            10000   /* equal value of King, losing King==mate */

/*
   Some board constants to make moves easier to read
 */
#define ONE_RANK (8)
#define TWO_RANKS (16)
#define UP (-8)
#define DOWN (8)
#define LEFT (-1)
#define RIGHT (1)
#define RIGHT_UP (RIGHT+UP)
#define LEFT_UP (LEFT+UP)
#define RIGHT_DOWN (RIGHT+DOWN)
#define LEFT_DOWN (LEFT+DOWN)

#define COL(pos) ((pos)&7)
#define ROW(pos) (((unsigned)pos)>>3)
/*
   ****************************************************************************
   * Board representation and main varians                                    *
   ****************************************************************************
 */
///* Board representation */
/* Board representation */
int             initial_piece[64] =
{
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
};

int             piece[64];

int             initial_color[64] =
{
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE
};

int             color[64];

int             side;           /* side to move, value = BLACK or WHITE */

/* For move generation */
#define MOVE_TYPE_NONE                  0
#define MOVE_TYPE_NORMAL                1
#define MOVE_TYPE_CASTLE                2
#define MOVE_TYPE_ENPASANT              3
#define MOVE_TYPE_PROMOTION_TO_QUEEN    4
#define MOVE_TYPE_PROMOTION_TO_ROOK     5
#define MOVE_TYPE_PROMOTION_TO_BISHOP   6
#define MOVE_TYPE_PROMOTION_TO_KNIGHT   7


typedef struct tag_MOVE {
    int             from,
                    dest,
                    type;
}               MOVE;
/* For storing all moves of game */
typedef struct tag_HIST {
    MOVE            m;
    int             cap;
}               HIST;

HIST            hist[6000];     /* Game length < 6000 */

int             hdp;            /* Current move order */

/* For searching */
int             nodes;          /* Count all visited nodes when searching */
int             ply;            /* ply of search */

/*
   ****************************************************************************
   * Move generator                                                           *
   * Lack: no enpassant, no castle                                            *
   ****************************************************************************
 */
void            Gen_Push(int from, int dest, int type, MOVE * pBuf, int *pMCount)
{
    MOVE            move;
    move.from = from;
    move.dest = dest;
    move.type = type;
    pBuf[*pMCount] = move;
    *pMCount = *pMCount + 1;
}

void            Gen_PushNormal(int from, int dest, MOVE * pBuf, int *pMCount)
{
    Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
}

/* Pawn can promote */
void            Gen_PushPawn(int from, int dest, MOVE * pBuf, int *pMCount)
{
    if (dest > 7 && dest < 56)
        Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
    else {
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount);
    }
}

/* Gen all moves of current_side to move and push them to pBuf, return number of moves */
int             Gen(int current_side, MOVE * pBuf)
{
    int             i,
                    k,
                    y,
                    row,
                    col,
                    movecount;
    movecount = 0;

    for (i = 0; i < 64; i++)    /* Scan all board */
        if (color[i] == current_side) {
            switch (piece[i]) {
            case PAWN:
                col = COL(i);
                row = ROW(i);
                if (current_side == BLACK) {
                    if (color[i + ONE_RANK] == EMPTY)
                        Gen_PushPawn(i, i + ONE_RANK, pBuf, &movecount);
                    if (row == 1 && color[i + ONE_RANK] == EMPTY && color[i + TWO_RANKS] == EMPTY)
                        Gen_PushNormal(i, i + TWO_RANKS, pBuf, &movecount);
                    if (col && color[i + 7] == WHITE)
                        Gen_PushNormal(i, i + 7, pBuf, &movecount);
                    if (col < 7 && color[i + 9] == WHITE)
                        Gen_PushNormal(i, i + 9, pBuf, &movecount);
                } else {
                    if (color[i - ONE_RANK] == EMPTY)
                        Gen_PushPawn(i, i - ONE_RANK, pBuf, &movecount);
                    if (row == 6 && color[i - ONE_RANK] == EMPTY && color[i - TWO_RANKS] == EMPTY)
                        Gen_PushNormal(i, i - TWO_RANKS, pBuf, &movecount);
                    if (col && color[i - 9] == BLACK)
                        Gen_PushNormal(i, i - 9, pBuf, &movecount);
                    if (col < 7 && color[i - 7] == BLACK)
                        Gen_PushNormal(i, i - 7, pBuf, &movecount);
                }
                break;

            case QUEEN:         /* == BISHOP+ROOK */
            case BISHOP:
                for (y = i - 9; y >= 0 && COL(y) != 7; y -= 9) {        /* go left up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 7; y >= 0 && COL(y) != 0; y -= 7) {        /* go right up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 9; y < 64 && COL(y) != 0; y += 9) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 7; y < 64 && COL(y) != 7; y += 7) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                if (piece[i] == BISHOP)
                    break;

                /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */
            case ROOK:
                col = COL(i);
                for (k = i - col, y = i - 1; y >= k; y--) {     /* go left */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (k = i - col + 7, y = i + 1; y <= k; y++) { /* go right */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 8; y >= 0; y -= 8) {       /* go up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 8; y < 64; y += 8) {       /* go down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                break;

            case KNIGHT:
                col = COL(i);
                y = i - 6;
                if (y >= 0 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 10;
                if (y >= 0 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 15;
                if (y >= 0 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 17;
                if (y >= 0 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 6;
                if (y < 64 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 10;
                if (y < 64 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 15;
                if (y < 64 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 17;
                if (y < 64 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                break;

            case KING:
                col = COL(i);
                if (col && color[i - 1] != current_side)
                    Gen_PushNormal(i, i - 1, pBuf, &movecount); /* left */
                if (col < 7 && color[i + 1] != current_side)
                    Gen_PushNormal(i, i + 1, pBuf, &movecount); /* right */
                if (i > 7 && color[i - 8] != current_side)
                    Gen_PushNormal(i, i - 8, pBuf, &movecount); /* up */
                if (i < 56 && color[i + 8] != current_side)
                    Gen_PushNormal(i, i + 8, pBuf, &movecount); /* down */
                if (col && i > 7 && color[i - 9] != current_side)
                    Gen_PushNormal(i, i - 9, pBuf, &movecount); /* left up */
                if (col < 7 && i > 7 && color[i - 7] != current_side)
                    Gen_PushNormal(i, i - 7, pBuf, &movecount); /* right up */
                if (col && i < 56 && color[i + 7] != current_side)
                    Gen_PushNormal(i, i + 7, pBuf, &movecount); /* left down */
                if (col < 7 && i < 56 && color[i + 9] != current_side)
                    Gen_PushNormal(i, i + 9, pBuf, &movecount); /* right down */
                break;
            default:
                puts("piece type unknown");
                assert(false);
            }
        }
    return movecount;
}

/*
   ****************************************************************************
   * Evaluation for current position - main "brain" function                  *
   * Lack: almost no knowlegde                                                *
   ****************************************************************************
 */
int             Eval()
{
    int             value_piece[6] =
    {VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN, VALUE_KING};
    int             i,
                    score = 0;
    for (i = 0; i < 64; i++) {
        if (color[i] == WHITE)
            score += value_piece[piece[i]];
        else if (color[i] == BLACK)
            score -= value_piece[piece[i]];
    }
    if (side == WHITE)
        return score;
    return -score;
}

/*
   ****************************************************************************
   * Make and Take back a move, IsInCheck                                     *
   ****************************************************************************
 */
/* Check and return 1 if side is in check */
int             IsInCheck(int current_side)
{
    int             k,
                    h,
                    y,
                    row,
                    col,
                    xside;
    xside = (WHITE + BLACK) - current_side;     /* opposite current_side, who
                                                 * may be checking */
    /* Find King */
    for (k = 0; k < 64; k++)
        if (piece[k] == KING && color[k] == current_side)
            break;

    row = ROW(k), col = COL(k);
    /* Check attacking of Knight */
    if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT)
        return 1;
    if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT)
        return 1;
    if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT)
        return 1;
    if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT)
        return 1;
    if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT)
        return 1;
    if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT)
        return 1;
    if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT)
        return 1;
    if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT)
        return 1;
    /* Check horizontal and vertical lines for attacking of Queen, Rook, King */
    /* go down */
    y = k + 8;
    if (y < 64) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y += 8; y < 64; y += 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left */
    y = k - 1;
    h = k - col;
    if (y >= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y--; y >= h; y--) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go right */
    y = k + 1;
    h = k - col + 7;
    if (y <= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y++; y <= h; y++) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go up */
    y = k - 8;
    if (y >= 0) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y -= 8; y >= 0; y -= 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */
    /* go right down */
    y = k + 9;
    if (y < 64 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 9; y < 64 && COL(y) != 0; y += 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go left down */
    y = k + 7;
    if (y < 64 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 7; y < 64 && COL(y) != 7; y += 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left up */
    y = k - 9;
    if (y >= 0 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 9; y >= 0 && COL(y) != 7; y -= 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go right up */
    y = k - 7;
    if (y >= 0 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 7; y >= 0 && COL(y) != 0; y -= 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    return 0;
}

int             MakeMove(MOVE m)
{
    int             r;
    hist[hdp].m = m;
    hist[hdp].cap = piece[m.dest];
    piece[m.dest] = piece[m.from];
    piece[m.from] = EMPTY;
    color[m.dest] = color[m.from];
    color[m.from] = EMPTY;
    if (m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) {       /* Promotion */
        switch (m.type) {
        case MOVE_TYPE_PROMOTION_TO_QUEEN:
            piece[m.dest] = QUEEN;
            break;

        case MOVE_TYPE_PROMOTION_TO_ROOK:
            piece[m.dest] = ROOK;
            break;

        case MOVE_TYPE_PROMOTION_TO_BISHOP:
            piece[m.dest] = BISHOP;
            break;

        case MOVE_TYPE_PROMOTION_TO_KNIGHT:
            piece[m.dest] = KNIGHT;
            break;

        default:
            puts("impossible to get here...");
            assert(false);
        }
    }
    ply++;
    hdp++;
    r = !IsInCheck(side);
    side = (WHITE + BLACK) - side;      /* After making move, give turn to
                                         * opponent */
    return r;
}

void            TakeBack()
{                               /* undo what MakeMove did */
    side = (WHITE + BLACK) - side;
    hdp--;
    ply--;
    piece[hist[hdp].m.from] = piece[hist[hdp].m.dest];
    piece[hist[hdp].m.dest] = hist[hdp].cap;
    color[hist[hdp].m.from] = side;
    if (hist[hdp].cap != EMPTY)
        color[hist[hdp].m.dest] = (WHITE + BLACK) - side;
    else
        color[hist[hdp].m.dest] = EMPTY;
    if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN)       /* Promotion */
        piece[hist[hdp].m.from] = PAWN;
}

/*
   ****************************************************************************
   * Search function - a typical alphabeta, main search function              *
   * Lack: no any technique for move ordering                                 *
   ****************************************************************************
 */

int             Search(int alpha, int beta, int depth, MOVE * pBestMove)
{
    int             i,
                    value,
                    havemove,
                    movecnt;
    MOVE            moveBuf[200],
                    tmpMove;

    nodes++;                    /* visiting a node, count it */
    havemove = 0;
    pBestMove->type = MOVE_TYPE_NONE;
    movecnt = Gen(side, moveBuf);       /* generate all moves for current
                                         * position */
    /* loop through the moves */
    for (i = 0; i < movecnt; ++i) {
        if (!MakeMove(moveBuf[i])) {
            TakeBack();
            continue;
        }
        havemove = 1;
        if (depth - 1 > 0)      /* If depth is still, continue to search
                                 * deeper */
            value = -Search(-beta, -alpha, depth - 1, &tmpMove);
        else                    /* If no depth left (leaf node), go to
                                 * evalute that position */
            value = Eval();
        TakeBack();
        if (value > alpha) {
            /* This move is so good and caused a cutoff */
            if (value >= beta)
                return beta;
            alpha = value;
            *pBestMove = moveBuf[i];    /* so far, current move is the best
                                         * reaction for current position */
        }
    }
    if (!havemove) {            /* If no legal moves, that is checkmate or
                                 * stalemate */
        if (IsInCheck(side))
            return -MATE + ply; /* add ply to find the longest path to lose
                                 * or shortest path to win */
        else
            return 0;
    }
    return alpha;
}

MOVE
ComputerThink(int max_depth)
{
    MOVE            m;
    int             score;
    /* reset some values before searching */
    ply = 0;
    nodes = 0;
    /* search now */
    score = Search(-MATE, MATE, max_depth, &m);
    /* after searching, print results */
    printf("Search result: move = %c%d%c%d; nodes = %d, score = %d\n",
           'a' + COL(m.from),
           8 - ROW(m.from),
           'a' + COL(m.dest),
           8 - ROW(m.dest),
           nodes,
           score
        );
    return m;
}

/*
   ****************************************************************************
   * Utilities                                                                *
   ****************************************************************************
 */
void            PrintBoard()
{
    char            pieceName[] = "PNBRQKpnbrqk";
    int             i;
    for (i = 0; i < 64; i++) {
        if ((i & 7) == 0) {
            printf("   +---+---+---+---+---+---+---+---+\n");
            if (i <= 56) {
                printf(" %d |", 8 - (((unsigned) i) >> 3));
            }
        }
        if (piece[i] == EMPTY)
            printf("   |");
        else {
            printf(" %c |", pieceName[piece[i] + (color[i] == WHITE ? 0 : 6)]);
        }
        if ((i & 7) == 7)
            printf("\n");
    }
    printf("   +---+---+---+---+---+---+---+---+\n     a   b   c   d   e   f   g   h\n");
}


void            initboard(void)
{
    memcpy(piece, initial_piece, sizeof piece);
    memcpy(color, initial_color, sizeof color);
}

/*
BUGBUG:DRC -->FIXME
globals are for the lazy and insane.
*/
int             xboard = 0;
int             computer_side = -1;
int             selfplay = 0;
int             nocomp = 0;
int             no_go = 0;
int             playing = 0;
int             player = WHITE;
int             maxtime = 1000;
int             max_depth = 5;
int             max_moves = 40;

/*
Shamelessly cobbled start of a Winboard interface
stolen from Jim Ablett's work on Vchess.

"Il pense à sa punition méritée."
-- dcorbit
*/
MOVE            getmove(int side, MOVE * moveBuf)
{


    MOVE            pmove = {0};

    int             moveind;
    int             movecnt;

    int             from,
                    dest,
                    i;
    char            cmd[256];
    char            inp[256];
    moveind = -1;

    while (moveind == -1) {
        if (!xboard) {
            puts("fc> ");
        } else {
            printf("\n");
        }
        if (!fgets(inp, sizeof inp, stdin))
            return pmove;
        if (inp[0] == '\n')
            continue;
        sscanf(inp, "%s", cmd);
        if (!strcmp(cmd, "go")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -2;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "self")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -3;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "back")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -4;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "undo")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -4;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "black")) {
            computer_side = BLACK;
            selfplay = false;
            nocomp = false;
            no_go = true;
            continue;
        } else if (!strcmp(cmd, "white")) {
            computer_side = WHITE;
            selfplay = false;
            nocomp = false;
            no_go = false;
            continue;
        } else if (!strcmp(cmd, "new")) {
            computer_side = BLACK;
            selfplay = false;
            nocomp = false;
            initboard();
            playing = true;
            player = WHITE;
            continue;
        } else if (!strcmp(cmd, "protover")) {
            printf("feature colors=1 myname=\"FirstChess Xboard 1.0\"");
            printf(" time=1 pause=0 ping=1 sigint=0 sigterm=0");
            printf(" name=1 reuse=0 done=1\n");
            continue;
        } else if (!strcmp(cmd, "force")) {
            nocomp = true;
            continue;
        } else if (!strcmp(cmd, "quit")) {
            exit(EXIT_SUCCESS);
        } else if (!strcmp(cmd, "easy")) {
            printf("easy (ponder off)\n");
            continue;
        } else if (!strcmp(cmd, "hard")) {
            printf("hard (ponder not implemented)\n");
            continue;
        } else if (!strcmp(cmd, "ping")) {
            int             ping;
            sscanf(inp, "%*s %d", &ping);
            printf("pong %d\n", ping);
            continue;
        } else if (!strcmp(cmd, "st")) {
            scanf(inp, "st %d", &maxtime);
            maxtime = (maxtime * 1000);
            max_depth = 32;
            continue;
        } else if (!strcmp(cmd, "time")) {
            sscanf(inp, "time %d", &maxtime);
            maxtime *= 14;
            maxtime /= (TIMEALLOC);
            max_depth = 15;
            continue;
        } else if (!strcmp(cmd, "level")) {
            sscanf(inp, "level %d %d", &max_moves, &maxtime);
            if (max_moves == 1);
            max_moves = (TIMEALLOC / 1000);
            maxtime *= 14;
            maxtime /= (max_moves * 1000);
            max_depth = 15;
            continue;
        } else if (!strcmp(cmd, "sd")) {
            sscanf(inp, "sd %d", &max_depth);
            maxtime = 1 << 25;
            continue;
        } else if (!strcmp(cmd, "otim")) {
            continue;
        } else if (!strcmp(cmd, "result")) {
            char            result[256];
            sscanf(inp, "result %s", result);
            nocomp = true;
            continue;
        } else if (!strcmp(cmd, "xboard")) {
            xboard = true;
            printf("feature done=0\n");
            continue;
        }
        /* user entered a move: */
        from = cmd[0] - 'a';
        from += 8 * (8 - (cmd[1] - '0'));
        dest = cmd[2] - 'a';
        dest += 8 * (8 - (cmd[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++) {
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (cmd[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

                if (xboard == false && moveind == -1)
                    printf("Error (unknown command): %s\n", cmd);
            }
            return (moveBuf[moveind]);
        } /* For loop over movecount */
    } /* While loop over moveind == -1 */
   assert(false);
   return pmove;
}

/*
   ****************************************************************************
   * Main program                                                             *
   ****************************************************************************
 */
int             main()
{
    char            s[256];
    int             from,
                    dest,
                    i;
    MOVE            moveBuf[200];
    int             movecnt;
    printf("First Chess, by Pham Hong Nguyen\n");
    printf("Help\n d: display board\n MOVE: make a move (e.g. b1c3, a7a8q)\n quit: exit\n\n");
    side = WHITE;
    computer_side = BLACK;      /* Human is white side */
    max_depth = 5;
    hdp = 0;
    initboard();
    for (;;) {
        if (side == computer_side) {    /* computer's turn */
            /* Find out the best move to react the current position */
            MOVE            bestMove = ComputerThink(max_depth);
            MakeMove(bestMove);
            continue;
        }
        /* get user input */
        printf("fc> ");
        if (scanf("%s", s) == EOF)      /* close program */
            return EXIT_FAILURE;
        if (!strcmp(s, "d")) {
            PrintBoard();
            continue;
        }
        if (!strcmp(s, "quit")) {
            printf("Good bye!\n");
            return EXIT_SUCCESS;
        }
        /* maybe the user entered a move? */
        from = s[0] - 'a';
        from += 8 * (8 - (s[1] - '0'));
        dest = s[2] - 'a';
        dest += 8 * (8 - (s[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++)
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (s[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

            }
    }
    return 0;
}

Dann Corbit
 

Re: Beginner programmer Winboard and chess computing advice

Postby H.G.Muller » 10 Jun 2009, 09:08

Interesting, I knew this Pham Hong Nguyen from the Xiangqi program VSCCP. Never knew he also wrote a Chess program.

The WinBoard driver in FirstChess is a bit mor minimalistic than what I woud recommend. At the very least you should implement the 'new' and 'level' commands to make your engine suitable for automatic play. The logic of the driver can remain the same, though. In pseudo-code:
Code: Select all
#include <signal.h>
int computerSide = NONE;

signal(SIGINT, SIG_IGN);
while(1)
{
     if(sideToMove == computerSide) {
        ThinkUpMove();
        MakeMove();
        PrintMove(); // "move ...."
        if(GameFinished()) { // optional
            PrintResult(); // 0-1, 1-0 or 1/2-1/2
            computerSide = NONE;
    }
    fflush(stdout); // VERY important!
    line = readLine();
    command = FirstWordOfLine();
    if(command == "quit" || EndOfFile()) {
        exit(0);
    } else
    if(command == "new") {
        SetUpNewGame(); // presumed to set sideToMove to WHITE
        computerSide = BLACK;
    } else
    if(command == "level") {
        ReadTimeControlParameters(line);
    } else
    if(command == "go") {
        computerSide = sideToMove;
    } else
    if(command == "time") {
        ReadTimeLeftAndAdjustClock();
    } else
    if(IsMove(command)) {
        if(LegalMove(command)) MakeMove(); // presumed to change sideToMove
        else printf("Illegal move: %s\n", command);
    } else
#ifdef OPTONAL_STUFF
    if(command == "protover") {
        printf("feature myname="John Doe" variants="normal" setboard=1 done=1\n");
    } else
    if(command == "setboard") {
        ReadAndSetupPosition(line); // FEN
        computerSide = NONE;
    } else
    if(command == "force") {
        computerSide = NONE;
    } else printf("Error (unknown command): %s\n", command);
#endif
}
User avatar
H.G.Muller
 
Posts: 3453
Joined: 16 Nov 2005, 12:02
Location: Diemen, NL

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 10 Jun 2009, 13:04

Hi guys (Dan & Hans)

Thanks very much for your helpful & prompt replies. I will now study the code you give & see how I get on.
I am very pleased you have the time for a beginner like me as I know you are 'experts' in the field!

Once again many thanks & best wishes to you
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby Dann Corbit » 10 Jun 2009, 19:56

H.G.Muller wrote:Interesting, I knew this Pham Hong Nguyen from the Xiangqi program VSCCP. Never knew he also wrote a Chess program.


He also wrote AxChess:
http://www.geocities.com/axchess/ax.html
Dann Corbit
 

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 10 Jun 2009, 21:13

Hi Dann

I have been looking at the code you gave this evening and so far I have not managed to use it with Winboard to play against!
Do you know what I am missing here? The code compiles & plays normally at the console for me as before- (& I can see several of your edits) did you manage to get FirstChess to play in Winboard?
I apologise if I have missed something basic here but I have also been searching on the net for signals in C & trying to figure out how to use Hans' pseudocode too but I am only a novice at programming......
I am grateful for any further advice & meanwhile I will continue to study & try to implement this, best wishes
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby Dann Corbit » 10 Jun 2009, 21:16

I just stuck in an approximate Winboard interface, but I did not even bother to connect it to the engine or add most of the hooks (e.g. when you to a time command it should modify something that the program uses).

You will need to change main() to something like this:
int main()
{
MOVE moveBuf[200];
MOVE bestMove;
printf("First Chess, by Pham Hong Nguyen\n");
printf("Help\n d: display board\n MOVE: make a move (e.g. b1c3, a7a8q)\n quit: exit\n\n");
side = WHITE;
computer_side = BLACK; /* Human is white side */
max_depth = 5;
hdp = 0;
initboard();
for (;;) {
if (side == computer_side) { /* computer's turn */
/* Find out the best move to react the current position */
bestMove = ComputerThink(max_depth);
MakeMove(bestMove);
continue;
}
/* get user input */
bestMove = getmove(!side, moveBuf);
}
return 0;
}

and also program all of the actions.

The only thing I gave you was a disconnected parser (with a few small starts of work thrown in).
Dann Corbit
 

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 10 Jun 2009, 22:15

Hi Dann

Thank you for your further input, which is most helpful. I still need to figure out how to program/code the other actions but I will try & work at it (sadly I have some other work to get on with also-so I cannot spend all my time on this & as I am not too clear about this yet it will probably take me somewhile to get this done). If I get too stuck I will ask for your help & advice again!
Meantime thanks again for your prompt reply and help, & again best wishes to you
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 13 Jun 2009, 17:25

Hi Dann
I have spent several hours more looking at this FirstChess code (& comparing it TSCP code that has Winboard supported), but I still cannot figure out the "actions" code I still need to implement to get it to work with Winboard (ie play a game in the Winboard GUI). Can you please help me some more?
Here I show the code I have presently (saved as FCDannCWB.c file):
Code: Select all

/*
   FirstChess - Freeware, by Pham Hong Nguyen
   Version: beta
*/
/*
   * BASIC PARTS:                          *
   * Some definitions                      *
   * Board representation and main varians *
   * Move generator                        *
   * Evaluation for current position       *
   * Make and Take back a move, IsInCheck  *
   * Search function - a typical alphabeta *
   * Utility                               *
   * Main program                          *
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define TIMEALLOC (55000)

typedef enum mybool {
false = 0, true = 1} mybool;
/*
   ****************************************************************************
   * Some definitions                                                         *
   ****************************************************************************
*/
#define   PAWN    0
#define   KNIGHT  1
#define   BISHOP  2
#define   ROOK    3
#define   QUEEN   4
#define   KING    5
#define   EMPTY   6
#define   WHITE   0
#define   BLACK   1

#define   VALUE_PAWN      100
#define   VALUE_KNIGHT    300
#define   VALUE_BISHOP    300
#define   VALUE_ROOK      500
#define   VALUE_QUEEN     900
#define   VALUE_KING      10000

#define   MATE            10000   /* equal value of King, losing King==mate */

/*
   Some board constants to make moves easier to read
*/
#define ONE_RANK (8)
#define TWO_RANKS (16)
#define UP (-8)
#define DOWN (8)
#define LEFT (-1)
#define RIGHT (1)
#define RIGHT_UP (RIGHT+UP)
#define LEFT_UP (LEFT+UP)
#define RIGHT_DOWN (RIGHT+DOWN)
#define LEFT_DOWN (LEFT+DOWN)

#define COL(pos) ((pos)&7)
#define ROW(pos) (((unsigned)pos)>>3)
/*
   ****************************************************************************
   * Board representation and main varians                                    *
   ****************************************************************************
*/
///* Board representation */
/* Board representation */
int             initial_piece[64] =
{
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
};

int             piece[64];

int             initial_color[64] =
{
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE
};

int             color[64];

int             side;           /* side to move, value = BLACK or WHITE */

/* For move generation */
#define MOVE_TYPE_NONE                  0
#define MOVE_TYPE_NORMAL                1
#define MOVE_TYPE_CASTLE                2
#define MOVE_TYPE_ENPASANT              3
#define MOVE_TYPE_PROMOTION_TO_QUEEN    4
#define MOVE_TYPE_PROMOTION_TO_ROOK     5
#define MOVE_TYPE_PROMOTION_TO_BISHOP   6
#define MOVE_TYPE_PROMOTION_TO_KNIGHT   7


typedef struct tag_MOVE {
    int             from,
                    dest,
                    type;
}               MOVE;
/* For storing all moves of game */
typedef struct tag_HIST {
    MOVE            m;
    int             cap;
}               HIST;

HIST            hist[6000];     /* Game length < 6000 */

int             hdp;            /* Current move order */

/* For searching */
int             nodes;          /* Count all visited nodes when searching */
int             ply;            /* ply of search */

/*
   ****************************************************************************
   * Move generator                                                           *
   * Lack: no enpassant, no castle                                            *
   ****************************************************************************
*/
void            Gen_Push(int from, int dest, int type, MOVE * pBuf, int *pMCount)
{
    MOVE            move;
    move.from = from;
    move.dest = dest;
    move.type = type;
    pBuf[*pMCount] = move;
    *pMCount = *pMCount + 1;
}

void            Gen_PushNormal(int from, int dest, MOVE * pBuf, int *pMCount)
{
    Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
}

/* Pawn can promote */
void            Gen_PushPawn(int from, int dest, MOVE * pBuf, int *pMCount)
{
    if (dest > 7 && dest < 56)
        Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
    else {
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount);
    }
}

/* Gen all moves of current_side to move and push them to pBuf, return number of moves */
int             Gen(int current_side, MOVE * pBuf)
{
    int             i,
                    k,
                    y,
                    row,
                    col,
                    movecount;
    movecount = 0;

    for (i = 0; i < 64; i++)    /* Scan all board */
        if (color[i] == current_side) {
            switch (piece[i]) {
            case PAWN:
                col = COL(i);
                row = ROW(i);
                if (current_side == BLACK) {
                    if (color[i + ONE_RANK] == EMPTY)
                        Gen_PushPawn(i, i + ONE_RANK, pBuf, &movecount);
                    if (row == 1 && color[i + ONE_RANK] == EMPTY && color[i + TWO_RANKS] == EMPTY)
                        Gen_PushNormal(i, i + TWO_RANKS, pBuf, &movecount);
                    if (col && color[i + 7] == WHITE)
                        Gen_PushNormal(i, i + 7, pBuf, &movecount);
                    if (col < 7 && color[i + 9] == WHITE)
                        Gen_PushNormal(i, i + 9, pBuf, &movecount);
                } else {
                    if (color[i - ONE_RANK] == EMPTY)
                        Gen_PushPawn(i, i - ONE_RANK, pBuf, &movecount);
                    if (row == 6 && color[i - ONE_RANK] == EMPTY && color[i - TWO_RANKS] == EMPTY)
                        Gen_PushNormal(i, i - TWO_RANKS, pBuf, &movecount);
                    if (col && color[i - 9] == BLACK)
                        Gen_PushNormal(i, i - 9, pBuf, &movecount);
                    if (col < 7 && color[i - 7] == BLACK)
                        Gen_PushNormal(i, i - 7, pBuf, &movecount);
                }
                break;

            case QUEEN:         /* == BISHOP+ROOK */
            case BISHOP:
                for (y = i - 9; y >= 0 && COL(y) != 7; y -= 9) {        /* go left up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 7; y >= 0 && COL(y) != 0; y -= 7) {        /* go right up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 9; y < 64 && COL(y) != 0; y += 9) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 7; y < 64 && COL(y) != 7; y += 7) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                if (piece[i] == BISHOP)
                    break;

                /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */
            case ROOK:
                col = COL(i);
                for (k = i - col, y = i - 1; y >= k; y--) {     /* go left */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (k = i - col + 7, y = i + 1; y <= k; y++) { /* go right */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 8; y >= 0; y -= 8) {       /* go up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 8; y < 64; y += 8) {       /* go down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                break;

            case KNIGHT:
                col = COL(i);
                y = i - 6;
                if (y >= 0 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 10;
                if (y >= 0 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 15;
                if (y >= 0 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 17;
                if (y >= 0 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 6;
                if (y < 64 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 10;
                if (y < 64 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 15;
                if (y < 64 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 17;
                if (y < 64 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                break;

            case KING:
                col = COL(i);
                if (col && color[i - 1] != current_side)
                    Gen_PushNormal(i, i - 1, pBuf, &movecount); /* left */
                if (col < 7 && color[i + 1] != current_side)
                    Gen_PushNormal(i, i + 1, pBuf, &movecount); /* right */
                if (i > 7 && color[i - 8] != current_side)
                    Gen_PushNormal(i, i - 8, pBuf, &movecount); /* up */
                if (i < 56 && color[i + 8] != current_side)
                    Gen_PushNormal(i, i + 8, pBuf, &movecount); /* down */
                if (col && i > 7 && color[i - 9] != current_side)
                    Gen_PushNormal(i, i - 9, pBuf, &movecount); /* left up */
                if (col < 7 && i > 7 && color[i - 7] != current_side)
                    Gen_PushNormal(i, i - 7, pBuf, &movecount); /* right up */
                if (col && i < 56 && color[i + 7] != current_side)
                    Gen_PushNormal(i, i + 7, pBuf, &movecount); /* left down */
                if (col < 7 && i < 56 && color[i + 9] != current_side)
                    Gen_PushNormal(i, i + 9, pBuf, &movecount); /* right down */
                break;
            default:
                puts("piece type unknown");
                assert(false);
            }
        }
    return movecount;
}

/*
   ****************************************************************************
   * Evaluation for current position - main "brain" function                  *
   * Lack: almost no knowlegde                                                *
   ****************************************************************************
*/
int             Eval()
{
    int             value_piece[6] =
    {VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN, VALUE_KING};
    int             i,
                    score = 0;
    for (i = 0; i < 64; i++) {
        if (color[i] == WHITE)
            score += value_piece[piece[i]];
        else if (color[i] == BLACK)
            score -= value_piece[piece[i]];
    }
    if (side == WHITE)
        return score;
    return -score;
}

/*
   ****************************************************************************
   * Make and Take back a move, IsInCheck                                     *
   ****************************************************************************
*/
/* Check and return 1 if side is in check */
int             IsInCheck(int current_side)
{
    int             k,
                    h,
                    y,
                    row,
                    col,
                    xside;
    xside = (WHITE + BLACK) - current_side;     /* opposite current_side, who
                                                 * may be checking */
    /* Find King */
    for (k = 0; k < 64; k++)
        if (piece[k] == KING && color[k] == current_side)
            break;

    row = ROW(k), col = COL(k);
    /* Check attacking of Knight */
    if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT)
        return 1;
    if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT)
        return 1;
    if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT)
        return 1;
    if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT)
        return 1;
    if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT)
        return 1;
    if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT)
        return 1;
    if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT)
        return 1;
    if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT)
        return 1;
    /* Check horizontal and vertical lines for attacking of Queen, Rook, King */
    /* go down */
    y = k + 8;
    if (y < 64) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y += 8; y < 64; y += 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left */
    y = k - 1;
    h = k - col;
    if (y >= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y--; y >= h; y--) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go right */
    y = k + 1;
    h = k - col + 7;
    if (y <= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y++; y <= h; y++) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go up */
    y = k - 8;
    if (y >= 0) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y -= 8; y >= 0; y -= 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */
    /* go right down */
    y = k + 9;
    if (y < 64 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 9; y < 64 && COL(y) != 0; y += 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go left down */
    y = k + 7;
    if (y < 64 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 7; y < 64 && COL(y) != 7; y += 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left up */
    y = k - 9;
    if (y >= 0 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 9; y >= 0 && COL(y) != 7; y -= 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go right up */
    y = k - 7;
    if (y >= 0 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 7; y >= 0 && COL(y) != 0; y -= 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    return 0;
}

int             MakeMove(MOVE m)
{
    int             r;
    hist[hdp].m = m;
    hist[hdp].cap = piece[m.dest];
    piece[m.dest] = piece[m.from];
    piece[m.from] = EMPTY;
    color[m.dest] = color[m.from];
    color[m.from] = EMPTY;
    if (m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) {       /* Promotion */
        switch (m.type) {
        case MOVE_TYPE_PROMOTION_TO_QUEEN:
            piece[m.dest] = QUEEN;
            break;

        case MOVE_TYPE_PROMOTION_TO_ROOK:
            piece[m.dest] = ROOK;
            break;

        case MOVE_TYPE_PROMOTION_TO_BISHOP:
            piece[m.dest] = BISHOP;
            break;

        case MOVE_TYPE_PROMOTION_TO_KNIGHT:
            piece[m.dest] = KNIGHT;
            break;

        default:
            puts("impossible to get here...");
            assert(false);
        }
    }
    ply++;
    hdp++;
    r = !IsInCheck(side);
    side = (WHITE + BLACK) - side;      /* After making move, give turn to
                                         * opponent */
    return r;
}

void            TakeBack()
{                               /* undo what MakeMove did */
    side = (WHITE + BLACK) - side;
    hdp--;
    ply--;
    piece[hist[hdp].m.from] = piece[hist[hdp].m.dest];
    piece[hist[hdp].m.dest] = hist[hdp].cap;
    color[hist[hdp].m.from] = side;
    if (hist[hdp].cap != EMPTY)
        color[hist[hdp].m.dest] = (WHITE + BLACK) - side;
    else
        color[hist[hdp].m.dest] = EMPTY;
    if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN)       /* Promotion */
        piece[hist[hdp].m.from] = PAWN;
}

/*
   ****************************************************************************
   * Search function - a typical alphabeta, main search function              *
   * Lack: no any technique for move ordering                                 *
   ****************************************************************************
*/

int             Search(int alpha, int beta, int depth, MOVE * pBestMove)
{
    int             i,
                    value,
                    havemove,
                    movecnt;
    MOVE            moveBuf[200],
                    tmpMove;

    nodes++;                    /* visiting a node, count it */
    havemove = 0;
    pBestMove->type = MOVE_TYPE_NONE;
    movecnt = Gen(side, moveBuf);       /* generate all moves for current
                                         * position */
    /* loop through the moves */
    for (i = 0; i < movecnt; ++i) {
        if (!MakeMove(moveBuf[i])) {
            TakeBack();
            continue;
        }
        havemove = 1;
        if (depth - 1 > 0)      /* If depth is still, continue to search
                                 * deeper */
            value = -Search(-beta, -alpha, depth - 1, &tmpMove);
        else                    /* If no depth left (leaf node), go to
                                 * evalute that position */
            value = Eval();
        TakeBack();
        if (value > alpha) {
            /* This move is so good and caused a cutoff */
            if (value >= beta)
                return beta;
            alpha = value;
            *pBestMove = moveBuf[i];    /* so far, current move is the best
                                         * reaction for current position */
        }
    }
    if (!havemove) {            /* If no legal moves, that is checkmate or
                                 * stalemate */
        if (IsInCheck(side))
            return -MATE + ply; /* add ply to find the longest path to lose
                                 * or shortest path to win */
        else
            return 0;
    }
    return alpha;
}

MOVE
ComputerThink(int max_depth)
{
    MOVE            m;
    int             score;
    /* reset some values before searching */
    ply = 0;
    nodes = 0;
    /* search now */
    score = Search(-MATE, MATE, max_depth, &m);
    /* after searching, print results */
    printf("Search result: move = %c%d%c%d; nodes = %d, score = %d\n",
           'a' + COL(m.from),
           8 - ROW(m.from),
           'a' + COL(m.dest),
           8 - ROW(m.dest),
           nodes,
           score
        );
    return m;
}

/*
   ****************************************************************************
   * Utilities                                                                *
   ****************************************************************************
*/
void            PrintBoard()
{
    char            pieceName[] = "PNBRQKpnbrqk";
    int             i;
    for (i = 0; i < 64; i++) {
        if ((i & 7) == 0) {
            printf("   +---+---+---+---+---+---+---+---+\n");
            if (i <= 56) {
                printf(" %d |", 8 - (((unsigned) i) >> 3));
            }
        }
        if (piece[i] == EMPTY)
            printf("   |");
        else {
            printf(" %c |", pieceName[piece[i] + (color[i] == WHITE ? 0 : 6)]);
        }
        if ((i & 7) == 7)
            printf("\n");
    }
    printf("   +---+---+---+---+---+---+---+---+\n     a   b   c   d   e   f   g   h\n");
}


void            initboard(void)
{
    memcpy(piece, initial_piece, sizeof piece);
    memcpy(color, initial_color, sizeof color);
}

/*
BUGBUG:DRC -->FIXME
globals are for the lazy and insane.
*/
int             xboard = 0;
int             computer_side = -1;
int             selfplay = 0;
int             nocomp = 0;
int             no_go = 0;
int             playing = 0;
int             player = WHITE;
int             maxtime = 1000;
int             max_depth = 5;
int             max_moves = 40;

/*
Shamelessly cobbled start of a Winboard interface
stolen from Jim Ablett's work on Vchess.

"Il pense à sa punition méritée."
-- dcorbit
*/
MOVE            getmove(int side, MOVE * moveBuf)
{


    MOVE            pmove = {0};

    int             moveind;
    int             movecnt;

    int             from,
                    dest,
                    i;
    char            cmd[256];
    char            inp[256];
    moveind = -1;

    while (moveind == -1) {
        if (!xboard) {
            puts("fc> ");
        } else {
            printf("\n");
        }
        if (!fgets(inp, sizeof inp, stdin))
            return pmove;
        if (inp[0] == '\n')
            continue;
        sscanf(inp, "%s", cmd);
        if (!strcmp(cmd, "go")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -2;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "self")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -3;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "back")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -4;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "undo")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -4;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "black")) {
            computer_side = BLACK;
            selfplay = false;
            nocomp = false;
            no_go = true;
            continue;
        } else if (!strcmp(cmd, "white")) {
            computer_side = WHITE;
            selfplay = false;
            nocomp = false;
            no_go = false;
            continue;
        } else if (!strcmp(cmd, "new")) {
            computer_side = BLACK;
            selfplay = false;
            nocomp = false;
            initboard();
            playing = true;
            player = WHITE;
            continue;
        } else if (!strcmp(cmd, "protover")) {
            printf("feature colors=1 myname=\"FirstChess Xboard 1.0\"");
            printf(" time=1 pause=0 ping=1 sigint=0 sigterm=0");
            printf(" name=1 reuse=0 done=1\n");
            continue;
        } else if (!strcmp(cmd, "force")) {
            nocomp = true;
            continue;
        } else if (!strcmp(cmd, "quit")) {
            exit(EXIT_SUCCESS);
        } else if (!strcmp(cmd, "easy")) {
            printf("easy (ponder off)\n");
            continue;
        } else if (!strcmp(cmd, "hard")) {
            printf("hard (ponder not implemented)\n");
            continue;
        } else if (!strcmp(cmd, "ping")) {
            int             ping;
            sscanf(inp, "%*s %d", &ping);
            printf("pong %d\n", ping);
            continue;
        } else if (!strcmp(cmd, "st")) {
            scanf(inp, "st %d", &maxtime);
            maxtime = (maxtime * 1000);
            max_depth = 32;
            continue;
        } else if (!strcmp(cmd, "time")) {
            sscanf(inp, "time %d", &maxtime);
            maxtime *= 14;
            maxtime /= (TIMEALLOC);
            max_depth = 15;
            continue;
        } else if (!strcmp(cmd, "level")) {
            sscanf(inp, "level %d %d", &max_moves, &maxtime);
            if (max_moves == 1);
            max_moves = (TIMEALLOC / 1000);
            maxtime *= 14;
            maxtime /= (max_moves * 1000);
            max_depth = 15;
            continue;
        } else if (!strcmp(cmd, "sd")) {
            sscanf(inp, "sd %d", &max_depth);
            maxtime = 1 << 25;
            continue;
        } else if (!strcmp(cmd, "otim")) {
            continue;
        } else if (!strcmp(cmd, "result")) {
            char            result[256];
            sscanf(inp, "result %s", result);
            nocomp = true;
            continue;
        } else if (!strcmp(cmd, "xboard")) {
            xboard = true;
            printf("feature done=0\n");
            continue;
        }
        /* user entered a move: */
        from = cmd[0] - 'a';
        from += 8 * (8 - (cmd[1] - '0'));
        dest = cmd[2] - 'a';
        dest += 8 * (8 - (cmd[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++) {
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (cmd[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

                if (xboard == false && moveind == -1)
                    printf("Error (unknown command): %s\n", cmd);
            }
            return (moveBuf[moveind]);
        } /* For loop over movecount */
    } /* While loop over moveind == -1 */
   assert(false);
   return pmove;
}

/*
   ****************************************************************************
   * Main program                                                             *
   ****************************************************************************
*/
int             main()
{
    char            s[256];
    int             from,
                    dest,
                    i;
    MOVE            moveBuf[200];
    MOVE            bestMove;
int             computer_side;
    int             max_depth;  /* max depth to search */
    int             movecnt;
    printf("First Chess, by Pham Hong Nguyen\n");
    printf("Help\n d: display board\n MOVE: make a move (e.g. b1c3, a7a8q)\n quit: exit\n\n");
    side = WHITE;
    computer_side = -1;      /* Human is white side */
    max_depth = 5;
    hdp = 0;
    initboard();
    for (;;) {
        fflush(stdout);
        if (side == computer_side) {    /* computer's turn */
/* Find out the best move to react the current position */
MOVE            bestMove = ComputerThink(max_depth);

MakeMove(bestMove);
continue;
        }
        /* get user input */
       
        bestMove = getmove(!side, moveBuf);
}
return 0;


       
        /* maybe the user entered a move? */
        from = s[0] - 'a';
        from += 8 * (8 - (s[1] - '0'));
        dest = s[2] - 'a';
        dest += 8 * (8 - (s[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++)
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (s[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

            }
    }
 


I am most grateful for your further help and reply, best wishes
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 14 Jun 2009, 23:35

Hi
I have been trying to get this to work but still no success. I am posting here my last failed attempt code and I would greatly appreciate some further help or guidance.
Currently on starting Winboard with the FirstChess.exe engine as coded I obtain a 'starting chess program' message print out and the title bar of Winboard GUI prints out the specified engine name (FirstChess Xboard 1.0) but when I make a move as white I get no response & black's flag falls!
I will keep trying to get this done by myself but a bit more help would be much appreciated!
I look forward to any further helpful replies,thanks

Code: Select all

/*
        FirstChess - Freeware, by Pham Hong Nguyen
        Version: beta
*/
/*
* BASIC PARTS:                                                             *
* Some definitions                                                         *
* Board representation and main varians                                    *
* Move generator                                                           *
* Evaluation for current position                                          *
* Make and Take back a move, IsInCheck                                     *
* Search function - a typical alphabeta                                    *
* Utility                                                                  *
* Main program                                                             *
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#define TIMEALLOC (55000)

typedef enum mybool {
false = 0, true = 1} mybool;

/*
****************************************************************************
* Some definitions                                                         *
****************************************************************************
*/
#define   PAWN    0
#define   KNIGHT  1
#define   BISHOP  2
#define   ROOK    3
#define   QUEEN   4
#define   KING    5
#define   EMPTY   6
#define   WHITE   0
#define   BLACK   1

#define   VALUE_PAWN      100
#define   VALUE_KNIGHT    300
#define   VALUE_BISHOP    300
#define   VALUE_ROOK      500
#define   VALUE_QUEEN     900
#define   VALUE_KING      10000

#define   MATE            10000 /* equal value of King, losing King==mate */

#define COL(pos) ((pos)&7)
#define ROW(pos) (((unsigned)pos)>>3)
/*
****************************************************************************
* Board representation and main varians                                    *
****************************************************************************
*/
/* Board representation */
int        initial_piece[64] = {
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
};

int             piece[64];

int      initial_color[64] = {
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE
};
int             color[64];
int             side;           /* side to move, value = BLACK or WHITE */

/* For move generation */
#define MOVE_TYPE_NONE                  0
#define MOVE_TYPE_NORMAL                1
#define MOVE_TYPE_CASTLE                2
#define MOVE_TYPE_ENPASANT              3
#define MOVE_TYPE_PROMOTION_TO_QUEEN    4
#define MOVE_TYPE_PROMOTION_TO_ROOK     5
#define MOVE_TYPE_PROMOTION_TO_BISHOP   6
#define MOVE_TYPE_PROMOTION_TO_KNIGHT   7


typedef struct tag_MOVE {
    int             from,
                    dest,
                    type;
}               MOVE;
/* For storing all moves of game */
typedef struct tag_HIST {
    MOVE            m;
    int             cap;
}               HIST;

HIST            hist[6000];     /* Game length < 6000 */

int             hdp;            /* Current move order */

/* For searching */
int             nodes;          /* Count all visited nodes when searching */
int             ply;            /* ply of search */

/*
****************************************************************************
* Move generator                                                           *
* Lack: no enpassant, no castle                                            *
****************************************************************************
*/
void            Gen_Push(int from, int dest, int type, MOVE * pBuf, int *pMCount)
{
    MOVE            move;
    move.from = from;
    move.dest = dest;
    move.type = type;
    pBuf[*pMCount] = move;
    *pMCount = *pMCount + 1;
}

void            Gen_PushNormal(int from, int dest, MOVE * pBuf, int *pMCount)
{
    Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
}

/* Pawn can promote */
void            Gen_PushPawn(int from, int dest, MOVE * pBuf, int *pMCount)
{
    if (dest > 7 && dest < 56)
        Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
    else {
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount);
    }
}

/* Gen all moves of current_side to move and push them to pBuf, return number of moves */
int             Gen(int current_side, MOVE * pBuf)
{
    int             i,
                    k,
                    y,
                    row,
                    col,
                    movecount;
    movecount = 0;

    for (i = 0; i < 64; i++)   /* Scan all board */
        if (color[i] == current_side) {
            switch (piece[i]) {
            case PAWN:
                col = COL(i);
                row = ROW(i);
                if (current_side == BLACK) {
                    if (color[i + 8] == EMPTY)
                        Gen_PushPawn(i, i + 8, pBuf, &movecount);
                    if (row == 1 && color[i + 8] == EMPTY && color[i + 16] == EMPTY)
                        Gen_PushNormal(i, i + 16, pBuf, &movecount);
                    if (col && color[i + 7] == WHITE)
                        Gen_PushNormal(i, i + 7, pBuf, &movecount);
                    if (col < 7 && color[i + 9] == WHITE)
                        Gen_PushNormal(i, i + 9, pBuf, &movecount);
                } else {
                    if (color[i - 8] == EMPTY)
                        Gen_PushPawn(i, i - 8, pBuf, &movecount);
                    if (row == 6 && color[i - 8] == EMPTY && color[i - 16] == EMPTY)
                        Gen_PushNormal(i, i - 16, pBuf, &movecount);
                    if (col && color[i - 9] == BLACK)
                        Gen_PushNormal(i, i - 9, pBuf, &movecount);
                    if (col < 7 && color[i - 7] == BLACK)
                        Gen_PushNormal(i, i - 7, pBuf, &movecount);
                }
                break;

            case QUEEN:         /* == BISHOP+ROOK */
            case BISHOP:
                for (y = i - 9; y >= 0 && COL(y) != 7; y -= 9) {        /* go left up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 7; y >= 0 && COL(y) != 0; y -= 7) {        /* go right up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 9; y < 64 && COL(y) != 0; y += 9) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 7; y < 64 && COL(y) != 7; y += 7) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                if (piece[i] == BISHOP)
                    break;

            /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */
            case ROOK:
                col = COL(i);
                for (k = i - col, y = i - 1; y >= k; y--) {  /* go left */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (k = i - col + 7, y = i + 1; y <= k; y++) {      /* go right */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 8; y >= 0; y -= 8) {       /* go up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 8; y < 64; y += 8) {       /* go down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                break;

            case KNIGHT:
                col = COL(i);
                y = i - 6;
                if (y >= 0 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 10;
                if (y >= 0 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 15;
                if (y >= 0 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 17;
                if (y >= 0 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 6;
                if (y < 64 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 10;
                if (y < 64 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 15;
                if (y < 64 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 17;
                if (y < 64 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                break;

            case KING:
                col = COL(i);
                if (col && color[i - 1] != current_side)
                    Gen_PushNormal(i, i - 1, pBuf, &movecount); /* left */
                if (col < 7 && color[i + 1] != current_side)
                    Gen_PushNormal(i, i + 1, pBuf, &movecount); /* right */
                if (i > 7 && color[i - 8] != current_side)
                    Gen_PushNormal(i, i - 8, pBuf, &movecount); /* up */
                if (i < 56 && color[i + 8] != current_side)
                    Gen_PushNormal(i, i + 8, pBuf, &movecount); /* down */
                if (col && i > 7 && color[i - 9] != current_side)
                    Gen_PushNormal(i, i - 9, pBuf, &movecount); /* left up */
                if (col < 7 && i > 7 && color[i - 7] != current_side)
                    Gen_PushNormal(i, i - 7, pBuf, &movecount); /* right up */
                if (col && i < 56 && color[i + 7] != current_side)
                    Gen_PushNormal(i, i + 7, pBuf, &movecount); /* left down */
                if (col < 7 && i < 56 && color[i + 9] != current_side)
                    Gen_PushNormal(i, i + 9, pBuf, &movecount); /* right down */
                break;
            default:
                puts("piece type unknown");
                assert(false);
            }
        }
    return movecount;
}

/*
****************************************************************************
* Evaluation for current position - main "brain" function                  *
* Lack: almost no knowlegde                                                *
****************************************************************************
*/
int             Eval()
{
    int             value_piece[6] = {VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN, VALUE_KING};
    int             i,
                    score = 0;
    for (i = 0; i < 64; i++) {
        if (color[i] == WHITE)
            score += value_piece[piece[i]];
        else if (color[i] == BLACK)
            score -= value_piece[piece[i]];
    }
    if (side == WHITE)
        return score;
    return -score;
}

/*
****************************************************************************
* Make and Take back a move, IsInCheck                                     *
****************************************************************************
*/
/* Check and return 1 if side is in check */
int             IsInCheck(int current_side)
{
    int             k,
                    h,
                    y,
                    row,
                    col,
                    xside;
    xside = (WHITE + BLACK) - current_side;     /* opposite current_side, who may be checking */
    /* Find King */
    for (k = 0; k < 64; k++)
        if (piece[k] == KING && color[k] == current_side)
            break;

    row = ROW(k), col = COL(k);
    /* Check attacking of Knight */
    if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT)
        return 1;
    if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT)
        return 1;
    if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT)
        return 1;
    if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT)
        return 1;
    if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT)
        return 1;
    if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT)
        return 1;
    if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT)
        return 1;
    if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT)
        return 1;
    /* Check horizontal and vertical lines for attacking of Queen, Rook, King */
    /* go down */
    y = k + 8;
    if (y < 64) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y += 8; y < 64; y += 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left */
    y = k - 1;
    h = k - col;
    if (y >= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y--; y >= h; y--) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go right */
    y = k + 1;
    h = k - col + 7;
    if (y <= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y++; y <= h; y++) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go up */
    y = k - 8;
    if (y >= 0) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y -= 8; y >= 0; y -= 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */
    /* go right down */
    y = k + 9;
    if (y < 64 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 9; y < 64 && COL(y) != 0; y += 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go left down */
    y = k + 7;
    if (y < 64 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 7; y < 64 && COL(y) != 7; y += 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left up */
    y = k - 9;
    if (y >= 0 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 9; y >= 0 && COL(y) != 7; y -= 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go right up */
    y = k - 7;
    if (y >= 0 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 7; y >= 0 && COL(y) != 0; y -= 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    return 0;
}

int             MakeMove(MOVE m)
{
    int             r;
    hist[hdp].m = m;
    hist[hdp].cap = piece[m.dest];
    piece[m.dest] = piece[m.from];
    piece[m.from] = EMPTY;
    color[m.dest] = color[m.from];
    color[m.from] = EMPTY;
    if (m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) {       /* Promotion */
        switch (m.type) {
        case MOVE_TYPE_PROMOTION_TO_QUEEN:
            piece[m.dest] = QUEEN;
            break;

        case MOVE_TYPE_PROMOTION_TO_ROOK:
            piece[m.dest] = ROOK;
            break;

        case MOVE_TYPE_PROMOTION_TO_BISHOP:
            piece[m.dest] = BISHOP;
            break;

        case MOVE_TYPE_PROMOTION_TO_KNIGHT:
            piece[m.dest] = KNIGHT;
            break;

        default:
            puts("impossible to get here...");
            assert(false);
        }
    }
    ply++;
    hdp++;
    r = !IsInCheck(side);
    side = (WHITE + BLACK) - side;      /* After making move, give turn to
                                         * opponent */
    return r;
}

void            TakeBack() /* undo what MakeMove did */
{
    side = (WHITE + BLACK) - side;
    hdp--;
    ply--;
    piece[hist[hdp].m.from] = piece[hist[hdp].m.dest];
    piece[hist[hdp].m.dest] = hist[hdp].cap;
    color[hist[hdp].m.from] = side;
    if (hist[hdp].cap != EMPTY)
        color[hist[hdp].m.dest] = (WHITE + BLACK) - side;
    else
        color[hist[hdp].m.dest] = EMPTY;
    if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN)       /* Promotion */
        piece[hist[hdp].m.from] = PAWN;
}

/*
****************************************************************************
* Search function - a typical alphabeta, main search function              *
* Lack: no any technique for move ordering                                 *
****************************************************************************
*/

int             Search(int alpha, int beta, int depth, MOVE * pBestMove)
{
    int             i,
                    value,
                    havemove,
               movecnt;
    MOVE            moveBuf[200],
                    tmpMove;
   
    nodes++; /* visiting a node, count it */
    havemove = 0;
    pBestMove->type = MOVE_TYPE_NONE;
   movecnt = Gen(side, moveBuf); /* generate all moves for current position */
    /* loop through the moves */
    for (i = 0; i < movecnt; ++i) {
        if (!MakeMove(moveBuf[i])) {
            TakeBack();
            continue;
        }
        havemove = 1;
        if (depth - 1 > 0) /* If depth is still, continue to search deeper */
            value = -Search(-beta, -alpha, depth - 1, &tmpMove);
        else /* If no depth left (leaf node), go to evalute that position */
            value = Eval();
        TakeBack();
        if (value > alpha) {
            /* This move is so good and caused a cutoff */
            if (value >= beta)
                return beta;
            alpha = value;
            *pBestMove = moveBuf[i]; /* so far, current move is the best reaction
                             * for current position */
        }
    }
    if (!havemove) {            /* If no legal moves, that is checkmate or
                                 * stalemate */
        if (IsInCheck(side))
            return -MATE + ply; /* add ply to find the longest path to lose or shortest path to win */
        else
            return 0;
    }
    return alpha;
}

MOVE            ComputerThink(int max_depth)
{
    MOVE            m;
    int             score;
   /* reset some values before searching */
    ply = 0;
    nodes = 0;
   /* search now */
    score = Search(-MATE, MATE, max_depth, &m);
   /* after searching, print results */
    printf("Search result: move = %c%d%c%d; nodes = %d, score = %d\n",
           'a' + COL(m.from),
           8 - ROW(m.from),
           'a' + COL(m.dest),
           8 - ROW(m.dest),
           nodes,
           score
        );
    return m;
}

/*
****************************************************************************
* Utilities                                                                *
****************************************************************************
*/
void            PrintBoard()
{
    char            pieceName[] = "PNBRQKpnbrqk";
    int             i;
    for (i = 0; i < 64; i++) {
        if ((i & 7) == 0) {
            printf("   +---+---+---+---+---+---+---+---+\n");
            if (i <= 56) {
                printf(" %d |", 8 - (((unsigned)i) >> 3));
            }
        }
        if (piece[i] == EMPTY)
            printf("   |");
        else {
            printf(" %c |", pieceName[piece[i] + (color[i] == WHITE ? 0 : 6)]);
        }
        if ((i & 7) == 7)
            printf("\n");
    }
    printf("   +---+---+---+---+---+---+---+---+\n     a   b   c   d   e   f   g   h\n");
}

void            initboard(void)
{
    memcpy(piece, initial_piece, sizeof piece);
    memcpy(color, initial_color, sizeof color);
}

/*
BUGBUG:DRC -->FIXME
globals are for the lazy and insane.
*/
int             xboard=0;
int             computer_side = -1;
int             selfplay = 0;
int             nocomp = 0;
int             no_go = 0;
int             playing = 0;
int             player = WHITE;
int             maxtime = 1000;
int             max_depth = 5;
int             max_moves = 40;



/*
Shamelessly cobbled start of a Winboard interface
stolen from Jim Ablett's work on Vchess.

"Il pense à sa punition méritée."
-- dcorbit
*/
MOVE            getmove(int side, MOVE * moveBuf)
{


    MOVE            pmove = {0};

    int             moveind;
    int             movecnt;

    int             from,
                    dest,
                    i;
    char            cmd[256];
    char            inp[256];
    moveind = -1;

    while (moveind == -1) {
        if (!xboard) {
            puts("fc> ");
        } else {
            printf("\n");
        }
        if (!fgets(inp, sizeof inp, stdin))
            return pmove;
        if (inp[0] == '\n')
            continue;
        sscanf(inp, "%s", cmd);
        if (!strcmp(cmd, "go")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -2;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "self")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -3;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "back")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -4;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "undo")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -4;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "black")) {
            computer_side = BLACK;
            selfplay = false;
            nocomp = false;
            no_go = true;
            continue;
        } else if (!strcmp(cmd, "white")) {
            computer_side = WHITE;
            selfplay = false;
            nocomp = false;
            no_go = false;
            continue;
        } else if (!strcmp(cmd, "new")) {
            computer_side = BLACK;
            selfplay = false;
            nocomp = false;
            initboard();
            playing = true;
            player = WHITE;
            continue;
        } else if (!strcmp(cmd, "protover")) {
            printf("feature colors=1 myname=\"FirstChess Xboard 1.0\"");
            printf(" time=1 pause=0 ping=1 sigint=0 sigterm=0");
            printf(" name=1 reuse=0 done=1\n");
            continue;
        } else if (!strcmp(cmd, "force")) {
            nocomp = true;
            continue;
        } else if (!strcmp(cmd, "quit")) {
            exit(EXIT_SUCCESS);
        } else if (!strcmp(cmd, "easy")) {
            printf("easy (ponder off)\n");
            continue;
        } else if (!strcmp(cmd, "hard")) {
            printf("hard (ponder not implemented)\n");
            continue;
        } else if (!strcmp(cmd, "ping")) {
            int             ping;
            sscanf(inp, "%*s %d", &ping);
            printf("pong %d\n", ping);
            continue;
        } else if (!strcmp(cmd, "st")) {
            scanf(inp, "st %d", &maxtime);
            maxtime = (maxtime * 1000);
            max_depth = 32;
            continue;
        } else if (!strcmp(cmd, "time")) {
            sscanf(inp, "time %d", &maxtime);
            maxtime *= 14;
            maxtime /= (TIMEALLOC);
            max_depth = 15;
            continue;
        } else if (!strcmp(cmd, "level")) {
            sscanf(inp, "level %d %d", &max_moves, &maxtime);
            if (max_moves == 1);
            max_moves = (TIMEALLOC / 1000);
            maxtime *= 14;
            maxtime /= (max_moves * 1000);
            max_depth = 15;
            continue;
        } else if (!strcmp(cmd, "sd")) {
            sscanf(inp, "sd %d", &max_depth);
            maxtime = 1 << 25;
            continue;
        } else if (!strcmp(cmd, "otim")) {
            continue;
        } else if (!strcmp(cmd, "result")) {
            char            result[256];
            sscanf(inp, "result %s", result);
            nocomp = true;
            continue;
        } else if (!strcmp(cmd, "xboard")) {
            xboard = true;
            printf("feature done=0\n");
            continue;
        }
        /* user entered a move: */
        from = cmd[0] - 'a';
        from += 8 * (8 - (cmd[1] - '0'));
        dest = cmd[2] - 'a';
        dest += 8 * (8 - (cmd[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++) {
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (cmd[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

                if (xboard == false && moveind == -1)
                    printf("Error (unknown command): %s\n", cmd);
            }
            return (moveBuf[moveind]);
        } /* For loop over movecount */
    } /* While loop over moveind == -1 */
   assert(false);
   return pmove;
}
                 

/*
****************************************************************************
* Main program                                                             *
****************************************************************************
*/
int           main()
{
    char            cmd[256];         
    char            s[256];
    int             from,
                    dest,
                    i;
    int             computer_side;
    int             max_depth;  /* max depth to search */
    MOVE            moveBuf[200];
    MOVE            bestMove;
    int             movecnt;
    printf("First Chess, by Pham Hong Nguyen\n");
    printf("Help\n d: display board\n MOVE: make a move (e.g. b1c3, a7a8q)\n quit: exit\n\n");
    side = WHITE;
    computer_side = BLACK;      /* Human is white side */
    initboard();
    max_depth = 5;
    hdp = 0;
    for (;;) {
        signal(SIGINT, SIG_IGN);
        if (side == computer_side){
        fflush(stdout);
       
                  /* computer's turn */
            /* Find out the best move to react the current position */
            MOVE (s);
            MOVE            bestMove = ComputerThink(max_depth);
            MakeMove(bestMove);
            continue;
        }
        bestMove = getmove(!side, moveBuf);
        /* get user input */
        //printf("fc> ");
         printf("fc> ");
        if (scanf("%s", s) == EOF)      /* close program */
            return EXIT_FAILURE;           
       
        if (scanf("%s", s) == EOF) /* close program */
            return;
        if (!strcmp(s, "d")) {
            PrintBoard();
            continue;
        }
        if (!strcmp(s, "xboard")) {
         xboard;
         break;
      }
      if (strcmp(cmd, "go")){
        side = computer_side;
        continue;
      
        if (!strcmp(s, "quit")) {
            printf("Good bye!\n");
            return;
        }
       /* maybe the user entered a move? */
        from = s[0] - 'a';
        from += 8 * (8 - (s[1] - '0'));
        dest = s[2] - 'a';
        dest += 8 * (8 - (s[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++)
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (s[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

            }
       

            }
            }
            }


tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby H.G.Muller » 15 Jun 2009, 07:56

Why don't you start from the micro-Max source, if you want to have a very simple working WinBoard engine? It contains very general WB driver code, which I use in all my engines.

The only quirk in uMax is that it ues the same routine D() for searching a move to do, and actually performing it. So it is used as both Search(), MakeMove() or Seach()+MakeMove(), depending on its parameter settings. But that is easy enough to figure out.
User avatar
H.G.Muller
 
Posts: 3453
Joined: 16 Nov 2005, 12:02
Location: Diemen, NL

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 15 Jun 2009, 08:33

Hi Hans
Thanks for your suggestion. I have taken a very quick glance at micromax code so I will look at it more thoroughly now.
Regards
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby H.G.Muller » 15 Jun 2009, 13:41

My name is "Harm Geert", by the way, but just H.G. will do. :wink:
User avatar
H.G.Muller
 
Posts: 3453
Joined: 16 Nov 2005, 12:02
Location: Diemen, NL

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 15 Jun 2009, 18:44

My humble apologies H.G!!
Thanks for the correction & best wishes
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 20 Jun 2009, 23:50

Hi again
I would still greatly appreciate some more help to get FirstChess winboard capable.
I have spent some more time trying to understand the winboard code (& looking at TSCP & MicroMax & several other engine implementations) but I still cannot get the code right. I put here code from one of my last efforts (which gives a problem entering moves both at the console & in Winboard!). I feel I might be quite close to the solution for this but would really appreciate some more help now to finish this.
Here is the code:
Code: Select all
/*
   FirstChess - Freeware, by Pham Hong Nguyen
   Version: beta
*/
/*
   * BASIC PARTS:                          *
   * Some definitions                      *
   * Board representation and main varians *
   * Move generator                        *
   * Evaluation for current position       *
   * Make and Take back a move, IsInCheck  *
   * Search function - a typical alphabeta *
   * Utility                               *
   * Main program                          *
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#define TIMEALLOC (55000)

typedef enum mybool {
false = 0, true = 1} mybool;
/*
   ****************************************************************************
   * Some definitions                                                         *
   ****************************************************************************
*/
#define   PAWN    0
#define   KNIGHT  1
#define   BISHOP  2
#define   ROOK    3
#define   QUEEN   4
#define   KING    5
#define   EMPTY   6
#define   WHITE   0
#define   BLACK   1

#define   VALUE_PAWN      100
#define   VALUE_KNIGHT    300
#define   VALUE_BISHOP    300
#define   VALUE_ROOK      500
#define   VALUE_QUEEN     900
#define   VALUE_KING      10000

#define   MATE            10000   /* equal value of King, losing King==mate */

/*
   Some board constants to make moves easier to read
*/
#define ONE_RANK (8)
#define TWO_RANKS (16)
#define UP (-8)
#define DOWN (8)
#define LEFT (-1)
#define RIGHT (1)
#define RIGHT_UP (RIGHT+UP)
#define LEFT_UP (LEFT+UP)
#define RIGHT_DOWN (RIGHT+DOWN)
#define LEFT_DOWN (LEFT+DOWN)

#define COL(pos) ((pos)&7)
#define ROW(pos) (((unsigned)pos)>>3)
/*
   ****************************************************************************
   * Board representation and main varians                                    *
   ****************************************************************************
*/
///* Board representation */
/* Board representation */
int             initial_piece[64] =
{
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
};

int             piece[64];

int             initial_color[64] =
{
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE
};

int             color[64];

int             side;           /* side to move, value = BLACK or WHITE */

/* For move generation */
#define MOVE_TYPE_NONE                  0
#define MOVE_TYPE_NORMAL                1
#define MOVE_TYPE_CASTLE                2
#define MOVE_TYPE_ENPASANT              3
#define MOVE_TYPE_PROMOTION_TO_QUEEN    4
#define MOVE_TYPE_PROMOTION_TO_ROOK     5
#define MOVE_TYPE_PROMOTION_TO_BISHOP   6
#define MOVE_TYPE_PROMOTION_TO_KNIGHT   7


typedef struct tag_MOVE {
    int             from,
                    dest,
                    type;
}               MOVE;
/* For storing all moves of game */
typedef struct tag_HIST {
    MOVE            m;
    int             cap;
}               HIST;

HIST            hist[6000];     /* Game length < 6000 */

int             hdp;            /* Current move order */

/* For searching */
int             nodes;          /* Count all visited nodes when searching */
int             ply;            /* ply of search */

/*
   ****************************************************************************
   * Move generator                                                           *
   * Lack: no enpassant, no castle                                            *
   ****************************************************************************
*/
void            Gen_Push(int from, int dest, int type, MOVE * pBuf, int *pMCount)
{
    MOVE            move;
    move.from = from;
    move.dest = dest;
    move.type = type;
    pBuf[*pMCount] = move;
    *pMCount = *pMCount + 1;
}

void            Gen_PushNormal(int from, int dest, MOVE * pBuf, int *pMCount)
{
    Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
}

/* Pawn can promote */
void            Gen_PushPawn(int from, int dest, MOVE * pBuf, int *pMCount)
{
    if (dest > 7 && dest < 56)
        Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
    else {
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount);
    }
}

/* Gen all moves of current_side to move and push them to pBuf, return number of moves */
int             Gen(int current_side, MOVE * pBuf)
{
    int             i,
                    k,
                    y,
                    row,
                    col,
                    movecount;
    movecount = 0;

    for (i = 0; i < 64; i++)    /* Scan all board */
        if (color[i] == current_side) {
            switch (piece[i]) {
            case PAWN:
                col = COL(i);
                row = ROW(i);
                if (current_side == BLACK) {
                    if (color[i + ONE_RANK] == EMPTY)
                        Gen_PushPawn(i, i + ONE_RANK, pBuf, &movecount);
                    if (row == 1 && color[i + ONE_RANK] == EMPTY && color[i + TWO_RANKS] == EMPTY)
                        Gen_PushNormal(i, i + TWO_RANKS, pBuf, &movecount);
                    if (col && color[i + 7] == WHITE)
                        Gen_PushNormal(i, i + 7, pBuf, &movecount);
                    if (col < 7 && color[i + 9] == WHITE)
                        Gen_PushNormal(i, i + 9, pBuf, &movecount);
                } else {
                    if (color[i - ONE_RANK] == EMPTY)
                        Gen_PushPawn(i, i - ONE_RANK, pBuf, &movecount);
                    if (row == 6 && color[i - ONE_RANK] == EMPTY && color[i - TWO_RANKS] == EMPTY)
                        Gen_PushNormal(i, i - TWO_RANKS, pBuf, &movecount);
                    if (col && color[i - 9] == BLACK)
                        Gen_PushNormal(i, i - 9, pBuf, &movecount);
                    if (col < 7 && color[i - 7] == BLACK)
                        Gen_PushNormal(i, i - 7, pBuf, &movecount);
                }
                break;

            case QUEEN:         /* == BISHOP+ROOK */
            case BISHOP:
                for (y = i - 9; y >= 0 && COL(y) != 7; y -= 9) {        /* go left up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 7; y >= 0 && COL(y) != 0; y -= 7) {        /* go right up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 9; y < 64 && COL(y) != 0; y += 9) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 7; y < 64 && COL(y) != 7; y += 7) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                if (piece[i] == BISHOP)
                    break;

                /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */
            case ROOK:
                col = COL(i);
                for (k = i - col, y = i - 1; y >= k; y--) {     /* go left */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (k = i - col + 7, y = i + 1; y <= k; y++) { /* go right */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 8; y >= 0; y -= 8) {       /* go up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 8; y < 64; y += 8) {       /* go down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                break;

            case KNIGHT:
                col = COL(i);
                y = i - 6;
                if (y >= 0 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 10;
                if (y >= 0 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 15;
                if (y >= 0 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 17;
                if (y >= 0 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 6;
                if (y < 64 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 10;
                if (y < 64 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 15;
                if (y < 64 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 17;
                if (y < 64 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                break;

            case KING:
                col = COL(i);
                if (col && color[i - 1] != current_side)
                    Gen_PushNormal(i, i - 1, pBuf, &movecount); /* left */
                if (col < 7 && color[i + 1] != current_side)
                    Gen_PushNormal(i, i + 1, pBuf, &movecount); /* right */
                if (i > 7 && color[i - 8] != current_side)
                    Gen_PushNormal(i, i - 8, pBuf, &movecount); /* up */
                if (i < 56 && color[i + 8] != current_side)
                    Gen_PushNormal(i, i + 8, pBuf, &movecount); /* down */
                if (col && i > 7 && color[i - 9] != current_side)
                    Gen_PushNormal(i, i - 9, pBuf, &movecount); /* left up */
                if (col < 7 && i > 7 && color[i - 7] != current_side)
                    Gen_PushNormal(i, i - 7, pBuf, &movecount); /* right up */
                if (col && i < 56 && color[i + 7] != current_side)
                    Gen_PushNormal(i, i + 7, pBuf, &movecount); /* left down */
                if (col < 7 && i < 56 && color[i + 9] != current_side)
                    Gen_PushNormal(i, i + 9, pBuf, &movecount); /* right down */
                break;
            default:
                puts("piece type unknown");
                assert(false);
            }
        }
    return movecount;
}

/*
   ****************************************************************************
   * Evaluation for current position - main "brain" function                  *
   * Lack: almost no knowlegde                                                *
   ****************************************************************************
*/
int             Eval()
{
    int             value_piece[6] =
    {VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN, VALUE_KING};
    int             i,
                    score = 0;
    for (i = 0; i < 64; i++) {
        if (color[i] == WHITE)
            score += value_piece[piece[i]];
        else if (color[i] == BLACK)
            score -= value_piece[piece[i]];
    }
    if (side == WHITE)
        return score;
    return -score;
}

/*
   ****************************************************************************
   * Make and Take back a move, IsInCheck                                     *
   ****************************************************************************
*/
/* Check and return 1 if side is in check */
int             IsInCheck(int current_side)
{
    int             k,
                    h,
                    y,
                    row,
                    col,
                    xside;
    xside = (WHITE + BLACK) - current_side;     /* opposite current_side, who
                                                 * may be checking */
    /* Find King */
    for (k = 0; k < 64; k++)
        if (piece[k] == KING && color[k] == current_side)
            break;

    row = ROW(k), col = COL(k);
    /* Check attacking of Knight */
    if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT)
        return 1;
    if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT)
        return 1;
    if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT)
        return 1;
    if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT)
        return 1;
    if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT)
        return 1;
    if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT)
        return 1;
    if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT)
        return 1;
    if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT)
        return 1;
    /* Check horizontal and vertical lines for attacking of Queen, Rook, King */
    /* go down */
    y = k + 8;
    if (y < 64) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y += 8; y < 64; y += 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left */
    y = k - 1;
    h = k - col;
    if (y >= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y--; y >= h; y--) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go right */
    y = k + 1;
    h = k - col + 7;
    if (y <= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y++; y <= h; y++) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go up */
    y = k - 8;
    if (y >= 0) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y -= 8; y >= 0; y -= 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */
    /* go right down */
    y = k + 9;
    if (y < 64 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 9; y < 64 && COL(y) != 0; y += 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go left down */
    y = k + 7;
    if (y < 64 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 7; y < 64 && COL(y) != 7; y += 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left up */
    y = k - 9;
    if (y >= 0 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 9; y >= 0 && COL(y) != 7; y -= 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go right up */
    y = k - 7;
    if (y >= 0 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 7; y >= 0 && COL(y) != 0; y -= 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    return 0;
}

int             MakeMove(MOVE m)
{
    int             r;
    hist[hdp].m = m;
    hist[hdp].cap = piece[m.dest];
    piece[m.dest] = piece[m.from];
    piece[m.from] = EMPTY;
    color[m.dest] = color[m.from];
    color[m.from] = EMPTY;
    if (m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) {       /* Promotion */
        switch (m.type) {
        case MOVE_TYPE_PROMOTION_TO_QUEEN:
            piece[m.dest] = QUEEN;
            break;

        case MOVE_TYPE_PROMOTION_TO_ROOK:
            piece[m.dest] = ROOK;
            break;

        case MOVE_TYPE_PROMOTION_TO_BISHOP:
            piece[m.dest] = BISHOP;
            break;

        case MOVE_TYPE_PROMOTION_TO_KNIGHT:
            piece[m.dest] = KNIGHT;
            break;

        default:
            puts("impossible to get here...");
            assert(false);
        }
    }
    ply++;
    hdp++;
    r = !IsInCheck(side);
    side = (WHITE + BLACK) - side;      /* After making move, give turn to
                                         * opponent */
    return r;
}

void            TakeBack()
{                               /* undo what MakeMove did */
    side = (WHITE + BLACK) - side;
    hdp--;
    ply--;
    piece[hist[hdp].m.from] = piece[hist[hdp].m.dest];
    piece[hist[hdp].m.dest] = hist[hdp].cap;
    color[hist[hdp].m.from] = side;
    if (hist[hdp].cap != EMPTY)
        color[hist[hdp].m.dest] = (WHITE + BLACK) - side;
    else
        color[hist[hdp].m.dest] = EMPTY;
    if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN)       /* Promotion */
        piece[hist[hdp].m.from] = PAWN;
}

/*
   ****************************************************************************
   * Search function - a typical alphabeta, main search function              *
   * Lack: no any technique for move ordering                                 *
   ****************************************************************************
*/

int             Search(int alpha, int beta, int depth, MOVE * pBestMove)
{
    int             i,
                    value,
                    havemove,
                    movecnt;
    MOVE            moveBuf[200],
                    tmpMove;

    nodes++;                    /* visiting a node, count it */
    havemove = 0;
    pBestMove->type = MOVE_TYPE_NONE;
    movecnt = Gen(side, moveBuf);       /* generate all moves for current
                                         * position */
    /* loop through the moves */
    for (i = 0; i < movecnt; ++i) {
        if (!MakeMove(moveBuf[i])) {
            TakeBack();
            continue;
        }
        havemove = 1;
        if (depth - 1 > 0)      /* If depth is still, continue to search
                                 * deeper */
            value = -Search(-beta, -alpha, depth - 1, &tmpMove);
        else                    /* If no depth left (leaf node), go to
                                 * evalute that position */
            value = Eval();
        TakeBack();
        if (value > alpha) {
            /* This move is so good and caused a cutoff */
            if (value >= beta)
                return beta;
            alpha = value;
            *pBestMove = moveBuf[i];    /* so far, current move is the best
                                         * reaction for current position */
        }
    }
    if (!havemove) {            /* If no legal moves, that is checkmate or
                                 * stalemate */
        if (IsInCheck(side))
            return -MATE + ply; /* add ply to find the longest path to lose
                                 * or shortest path to win */
        else
            return 0;
    }
    return alpha;
}

MOVE
ComputerThink(int max_depth)
{
    MOVE            m;
    int             score;
    /* reset some values before searching */
    ply = 0;
    nodes = 0;
    /* search now */
    score = Search(-MATE, MATE, max_depth, &m);
    /* after searching, print results */
    printf("Search result: move = %c%d%c%d; nodes = %d, score = %d\n",
           'a' + COL(m.from),
           8 - ROW(m.from),
           'a' + COL(m.dest),
           8 - ROW(m.dest),
           nodes,
           score
        );
    return m;
}

/*
   ****************************************************************************
   * Utilities                                                                *
   ****************************************************************************
*/
void            PrintBoard()
{
    char            pieceName[] = "PNBRQKpnbrqk";
    int             i;
    for (i = 0; i < 64; i++) {
        if ((i & 7) == 0) {
            printf("   +---+---+---+---+---+---+---+---+\n");
            if (i <= 56) {
                printf(" %d |", 8 - (((unsigned) i) >> 3));
            }
        }
        if (piece[i] == EMPTY)
            printf("   |");
        else {
            printf(" %c |", pieceName[piece[i] + (color[i] == WHITE ? 0 : 6)]);
        }
        if ((i & 7) == 7)
            printf("\n");
    }
    printf("   +---+---+---+---+---+---+---+---+\n     a   b   c   d   e   f   g   h\n");
}


void            initboard(void)
{
    memcpy(piece, initial_piece, sizeof piece);
    memcpy(color, initial_color, sizeof color);
}

/*
BUGBUG:DRC -->FIXME
globals are for the lazy and insane.
*/
int             xboard = 0;
int             computer_side = -1;
int             selfplay = 0;
int             nocomp = 0;
int             no_go = 0;
int             playing = 0;
int             player = WHITE;
int             maxtime = 1000;
int             max_depth = 5;
int             max_moves = 40;

/*
Shamelessly cobbled start of a Winboard interface
stolen from Jim Ablett's work on Vchess.

"Il pense à sa punition méritée."
-- dcorbit
*/

MOVE            getmove(int side, MOVE * moveBuf)
{


    MOVE            pmove = {0};

    int             moveind;
    int             movecnt;

    int             from,
                    dest,
                    i;
    char            cmd[256];
    char            inp[256];
    moveind = -1;

    while (moveind == -1) {
        if (!xboard) {
            puts("fc> ");
        } else {
            printf("\n");
        }
        if (!fgets(inp, sizeof inp, stdin))
            return pmove;
        if (inp[0] == '\n')
            continue;
        sscanf(inp, "%s", cmd);
        if (!strcmp(cmd, "go")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -2;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "self")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -3;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "back")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -4;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "undo")) {
            pmove.type = MOVE_TYPE_NONE;
            pmove.from = -4;
            return (pmove);
            continue;
        } else if (!strcmp(cmd, "black")) {
            computer_side = BLACK;
            selfplay = false;
            nocomp = false;
            no_go = true;
            continue;
        } else if (!strcmp(cmd, "white")) {
            computer_side = WHITE;
            selfplay = false;
            nocomp = false;
            no_go = false;
            continue;
        } else if (!strcmp(cmd, "new")) {
            computer_side = BLACK;
            selfplay = false;
            nocomp = false;
            initboard();
            playing = true;
            player = WHITE;
            continue;
        } else if (!strcmp(cmd, "protover")) {
            printf("feature colors=1 myname=\"FirstChess Xboard 1.0\"");
            printf(" time=1 pause=0 ping=1 sigint=0 sigterm=0");
            printf(" name=1 reuse=0 done=1\n");
            continue;
        } else if (!strcmp(cmd, "force")) {
            nocomp = true;
            continue;
        } else if (!strcmp(cmd, "quit")) {
            exit(EXIT_SUCCESS);
        } else if (!strcmp(cmd, "easy")) {
            printf("easy (ponder off)\n");
            continue;
        } else if (!strcmp(cmd, "hard")) {
            printf("hard (ponder not implemented)\n");
            continue;
        } else if (!strcmp(cmd, "ping")) {
            int             ping;
            sscanf(inp, "%*s %d", &ping);
            printf("pong %d\n", ping);
            continue;
        } else if (!strcmp(cmd, "st")) {
            scanf(inp, "st %d", &maxtime);
            maxtime = (maxtime * 1000);
            max_depth = 32;
            continue;
        } else if (!strcmp(cmd, "time")) {
            sscanf(inp, "time %d", &maxtime);
            maxtime *= 14;
            maxtime /= (TIMEALLOC);
            max_depth = 15;
            continue;
        } else if (!strcmp(cmd, "level")) {
            sscanf(inp, "level %d %d", &max_moves, &maxtime);
            if (max_moves == 1);
            max_moves = (TIMEALLOC / 1000);
            maxtime *= 14;
            maxtime /= (max_moves * 1000);
            max_depth = 15;
            continue;
        } else if (!strcmp(cmd, "sd")) {
            sscanf(inp, "sd %d", &max_depth);
            maxtime = 1 << 25;
            continue;
        } else if (!strcmp(cmd, "otim")) {
            continue;
        } else if (!strcmp(cmd, "result")) {
            char            result[256];
            sscanf(inp, "result %s", result);
            nocomp = true;
            continue;
        } else if (!strcmp(cmd, "xboard")) {
            xboard = true;
            printf("feature done=0\n");
            continue;
        }
        /* user entered a move: */
        from = cmd[0] - 'a';
        from += 8 * (8 - (cmd[1] - '0'));
        dest = cmd[2] - 'a';
        dest += 8 * (8 - (cmd[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++) {
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (cmd[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

                if (xboard == false && moveind == -1)
                    printf("Error (unknown command): %s\n", cmd);
            }
            return (moveBuf[moveind]);
        } /* For loop over movecount */
    } /* While loop over moveind == -1 */
   assert(false);
   return pmove;
}

/*
   ****************************************************************************
   * Main program                                                             *
   ****************************************************************************
*/
int             main()
{
    char  s[256];
    int             from,
                    dest,
                    i;
   
    MOVE  moveBuf[200];
    MOVE  bestMove;
    int   movecnt;
   
    printf("First Chess, by Pham Hong Nguyen\n");
    printf("Help\n d: display board\n MOVE: make a move (e.g. b1c3, a7a8q)\n quit: exit\n\n");
    side = WHITE;
    computer_side = BLACK;      /* Human is white side */
    max_depth = 5;
    hdp = 0;
    initboard();
    for (;;) {
        if (side == computer_side) {    /* computer's turn */
            /* Find out the best move to react the current position */
            bestMove = ComputerThink(max_depth);
            MakeMove(bestMove);
            continue;
        }
        if(!strcmp(s,"xboard")) {
            continue;
        }
        if (!strcmp(s,"new")) {
                        /* start new game */
                        initboard();
                             computer_side  = BLACK;
                                 continue;
      }
        /* get user input */
        bestMove = getmove(!side, moveBuf);
        printf("fc> ");
        if (scanf("%s", s) == EOF)      /* close program */
            return EXIT_FAILURE;
        if (!strcmp(s, "d")) {
            PrintBoard();
            continue;
        }
        if (!strcmp(s, "quit")) {
            printf("Good bye!\n");
            return EXIT_SUCCESS;
        }
        /* maybe the user entered a move? */
        from = s[0] - 'a';
        from += 8 * (8 - (s[1] - '0'));
        dest = s[2] - 'a';
        dest += 8 * (8 - (s[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++)
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (s[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

            }
    }
    return 0;
}



So I look forward to some more helpful replies, so that I may finish this code & have a good understanding of implementing the winboard protocol. With many thanks in advance for any forthcoming help for me with this,
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby Pedro Castro » 21 Jun 2009, 09:01

Hi tr2,

Here Firstchess with winboard protocol.
I have played on GUI Arena (command line parameter: xboard).
Firschess only play with depth fixed -- > menu "Level"/"Adjust"/"Fixed search depth" (4 is ok)

You can play a new game, switch color, takeback...

You can see the comunication --> menu "Engine"/Debug Window

But you will see play to Firstchess the same move, this is firstchess not protocol.

Best,

Pedro

Code: Select all
/*
        FirstChess - Freeware, by Pham Hong Nguyen
        Version: beta
*/
/*
* BASIC PARTS:                                                             *
* Some definitions                                                         *
* Board representation and main varians                                    *
* Move generator                                                           *
* Evaluation for current position                                          *
* Make and Take back a move, IsInCheck                                     *
* Search function - a typical alphabeta                                    *
* Utility                                                                  *
* Main program                                                             *
* New xboard protocol
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <signal.h>      //xboard

/*
****************************************************************************
* Some definitions                                                         *
****************************************************************************
*/
#define   PAWN    0
#define   KNIGHT  1
#define   BISHOP  2
#define   ROOK    3
#define   QUEEN   4
#define   KING    5
#define   EMPTY   6
#define   WHITE   0
#define   BLACK   1

#define   VALUE_PAWN      100
#define   VALUE_KNIGHT    300
#define   VALUE_BISHOP    300
#define   VALUE_ROOK      500
#define   VALUE_QUEEN     900
#define   VALUE_KING      10000

#define   MATE            10000 /* equal value of King, losing King==mate */

#define COL(pos) ((pos)&7)
#define ROW(pos) (((unsigned)pos)>>3)
/*
****************************************************************************
* Board representation and main varians                                    *
****************************************************************************
*/
/* Board representation */
int piece[64];
int color[64];

int             org_piece[64] = {
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
    ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
};

int             org_color[64] = {
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE,
    WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE
};

int             side;           /* side to move, value = BLACK or WHITE */
int             computer_side;
int             max_depth;  /* max depth to search */


/* For move generation */
#define MOVE_TYPE_NONE                  0
#define MOVE_TYPE_NORMAL                1
#define MOVE_TYPE_CASTLE                2
#define MOVE_TYPE_ENPASANT              3
#define MOVE_TYPE_PROMOTION_TO_QUEEN    4
#define MOVE_TYPE_PROMOTION_TO_ROOK     5
#define MOVE_TYPE_PROMOTION_TO_BISHOP   6
#define MOVE_TYPE_PROMOTION_TO_KNIGHT   7


typedef struct tag_MOVE {
    int             from,
                    dest,
                    type;
}               MOVE;
/* For storing all moves of game */
typedef struct tag_HIST {
    MOVE            m;
    int             cap;
}               HIST;

HIST            hist[6000];     /* Game length < 6000 */

int             hdp;            /* Current move order */

/* For searching */
int             nodes;          /* Count all visited nodes when searching */
int             ply;            /* ply of search */

int false;

/*
****************************************************************************
* Move generator                                                           *
* Lack: no enpassant, no castle                                            *
****************************************************************************
*/
void            Gen_Push(int from, int dest, int type, MOVE * pBuf, int *pMCount)
{
    MOVE            move;
    move.from = from;
    move.dest = dest;
    move.type = type;
    pBuf[*pMCount] = move;
    *pMCount = *pMCount + 1;
}

void            Gen_PushNormal(int from, int dest, MOVE * pBuf, int *pMCount)
{
    Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
}

/* Pawn can promote */
void            Gen_PushPawn(int from, int dest, MOVE * pBuf, int *pMCount)
{
    if (dest > 7 && dest < 56)
        Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
    else {
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount);
        Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount);
    }
}

/* Gen all moves of current_side to move and push them to pBuf, return number of moves */
int             Gen(int current_side, MOVE * pBuf)
{
    int             i,
                    k,
                    y,
                    row,
                    col,
                    movecount;
    movecount = 0;

    for (i = 0; i < 64; i++)   /* Scan all board */
        if (color[i] == current_side) {
            switch (piece[i]) {
            case PAWN:
                col = COL(i);
                row = ROW(i);
                if (current_side == BLACK) {
                    if (color[i + 8] == EMPTY)
                        Gen_PushPawn(i, i + 8, pBuf, &movecount);
                    if (row == 1 && color[i + 8] == EMPTY && color[i + 16] == EMPTY)
                        Gen_PushNormal(i, i + 16, pBuf, &movecount);
                    if (col && color[i + 7] == WHITE)
                        Gen_PushNormal(i, i + 7, pBuf, &movecount);
                    if (col < 7 && color[i + 9] == WHITE)
                        Gen_PushNormal(i, i + 9, pBuf, &movecount);
                } else {
                    if (color[i - 8] == EMPTY)
                        Gen_PushPawn(i, i - 8, pBuf, &movecount);
                    if (row == 6 && color[i - 8] == EMPTY && color[i - 16] == EMPTY)
                        Gen_PushNormal(i, i - 16, pBuf, &movecount);
                    if (col && color[i - 9] == BLACK)
                        Gen_PushNormal(i, i - 9, pBuf, &movecount);
                    if (col < 7 && color[i - 7] == BLACK)
                        Gen_PushNormal(i, i - 7, pBuf, &movecount);
                }
                break;

            case QUEEN:         /* == BISHOP+ROOK */
            case BISHOP:
                for (y = i - 9; y >= 0 && COL(y) != 7; y -= 9) {        /* go left up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 7; y >= 0 && COL(y) != 0; y -= 7) {        /* go right up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 9; y < 64 && COL(y) != 0; y += 9) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 7; y < 64 && COL(y) != 7; y += 7) {        /* go right down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                if (piece[i] == BISHOP)
                    break;

            /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */
            case ROOK:
                col = COL(i);
                for (k = i - col, y = i - 1; y >= k; y--) {  /* go left */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (k = i - col + 7, y = i + 1; y <= k; y++) {      /* go right */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i - 8; y >= 0; y -= 8) {       /* go up */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                for (y = i + 8; y < 64; y += 8) {       /* go down */
                    if (color[y] != current_side)
                        Gen_PushNormal(i, y, pBuf, &movecount);
                    if (color[y] != EMPTY)
                        break;

                }
                break;

            case KNIGHT:
                col = COL(i);
                y = i - 6;
                if (y >= 0 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 10;
                if (y >= 0 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 15;
                if (y >= 0 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i - 17;
                if (y >= 0 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 6;
                if (y < 64 && col > 1 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 10;
                if (y < 64 && col < 6 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 15;
                if (y < 64 && col > 0 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                y = i + 17;
                if (y < 64 && col < 7 && color[y] != current_side)
                    Gen_PushNormal(i, y, pBuf, &movecount);
                break;

            case KING:
                col = COL(i);
                if (col && color[i - 1] != current_side)
                    Gen_PushNormal(i, i - 1, pBuf, &movecount); /* left */
                if (col < 7 && color[i + 1] != current_side)
                    Gen_PushNormal(i, i + 1, pBuf, &movecount); /* right */
                if (i > 7 && color[i - 8] != current_side)
                    Gen_PushNormal(i, i - 8, pBuf, &movecount); /* up */
                if (i < 56 && color[i + 8] != current_side)
                    Gen_PushNormal(i, i + 8, pBuf, &movecount); /* down */
                if (col && i > 7 && color[i - 9] != current_side)
                    Gen_PushNormal(i, i - 9, pBuf, &movecount); /* left up */
                if (col < 7 && i > 7 && color[i - 7] != current_side)
                    Gen_PushNormal(i, i - 7, pBuf, &movecount); /* right up */
                if (col && i < 56 && color[i + 7] != current_side)
                    Gen_PushNormal(i, i + 7, pBuf, &movecount); /* left down */
                if (col < 7 && i < 56 && color[i + 9] != current_side)
                    Gen_PushNormal(i, i + 9, pBuf, &movecount); /* right down */
                break;
            default:
                puts("piece type unknown");
                assert(false);
            }
        }
    return movecount;
}

/*
****************************************************************************
* Evaluation for current position - main "brain" function                  *
* Lack: almost no knowlegde                                                *
****************************************************************************
*/
int             Eval()
{
    int             value_piece[6] = {VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN, VALUE_KING};
    int             i,
                    score = 0;
    for (i = 0; i < 64; i++) {
        if (color[i] == WHITE)
            score += value_piece[piece[i]];
        else if (color[i] == BLACK)
            score -= value_piece[piece[i]];
    }
    if (side == WHITE)
        return score;
    return -score;
}

/*
****************************************************************************
* Make and Take back a move, IsInCheck                                     *
****************************************************************************
*/
/* Check and return 1 if side is in check */
int             IsInCheck(int current_side)
{
    int             k,
                    h,
                    y,
                    row,
                    col,
                    xside;
    xside = (WHITE + BLACK) - current_side;     /* opposite current_side, who may be checking */
    /* Find King */
    for (k = 0; k < 64; k++)
        if (piece[k] == KING && color[k] == current_side)
            break;

    row = ROW(k), col = COL(k);
    /* Check attacking of Knight */
    if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT)
        return 1;
    if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT)
        return 1;
    if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT)
        return 1;
    if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT)
        return 1;
    if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT)
        return 1;
    if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT)
        return 1;
    if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT)
        return 1;
    if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT)
        return 1;
    /* Check horizontal and vertical lines for attacking of Queen, Rook, King */
    /* go down */
    y = k + 8;
    if (y < 64) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y += 8; y < 64; y += 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left */
    y = k - 1;
    h = k - col;
    if (y >= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y--; y >= h; y--) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go right */
    y = k + 1;
    h = k - col + 7;
    if (y <= h) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y++; y <= h; y++) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go up */
    y = k - 8;
    if (y >= 0) {
        if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
            return 1;
        if (piece[y] == EMPTY)
            for (y -= 8; y >= 0; y -= 8) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */
    /* go right down */
    y = k + 9;
    if (y < 64 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 9; y < 64 && COL(y) != 0; y += 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    /* go left down */
    y = k + 7;
    if (y < 64 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == BLACK && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y += 7; y < 64 && COL(y) != 7; y += 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go left up */
    y = k - 9;
    if (y >= 0 && COL(y) != 7) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 9; y >= 0 && COL(y) != 7; y -= 9) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;

            }
    }
    /* go right up */
    y = k - 7;
    if (y >= 0 && COL(y) != 0) {
        if (color[y] == xside) {
            if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
                return 1;
            if (current_side == WHITE && piece[y] == PAWN)
                return 1;
        }
        if (piece[y] == EMPTY)
            for (y -= 7; y >= 0 && COL(y) != 0; y -= 7) {
                if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
                    return 1;
                if (piece[y] != EMPTY)
                    break;
            }
    }
    return 0;
}

int             MakeMove(MOVE m)
{
    int             r;
    hist[hdp].m = m;
    hist[hdp].cap = piece[m.dest];
    piece[m.dest] = piece[m.from];
    piece[m.from] = EMPTY;
    color[m.dest] = color[m.from];
    color[m.from] = EMPTY;
    if (m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) {       /* Promotion */
        switch (m.type) {
        case MOVE_TYPE_PROMOTION_TO_QUEEN:
            piece[m.dest] = QUEEN;
            break;

        case MOVE_TYPE_PROMOTION_TO_ROOK:
            piece[m.dest] = ROOK;
            break;

        case MOVE_TYPE_PROMOTION_TO_BISHOP:
            piece[m.dest] = BISHOP;
            break;

        case MOVE_TYPE_PROMOTION_TO_KNIGHT:
            piece[m.dest] = KNIGHT;
            break;

        default:
            puts("impossible to get here...");
            assert(false);
        }
    }
    ply++;
    hdp++;
    r = !IsInCheck(side);
    side = (WHITE + BLACK) - side;      /* After making move, give turn to
                                         * opponent */
    return r;
}

void            TakeBack() /* undo what MakeMove did */
{
    side = (WHITE + BLACK) - side;
    hdp--;
    ply--;
    piece[hist[hdp].m.from] = piece[hist[hdp].m.dest];
    piece[hist[hdp].m.dest] = hist[hdp].cap;
    color[hist[hdp].m.from] = side;
    if (hist[hdp].cap != EMPTY)
        color[hist[hdp].m.dest] = (WHITE + BLACK) - side;
    else
        color[hist[hdp].m.dest] = EMPTY;
    if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN)       /* Promotion */
        piece[hist[hdp].m.from] = PAWN;
}

/*
****************************************************************************
* Search function - a typical alphabeta, main search function              *
* Lack: no any technique for move ordering                                 *
****************************************************************************
*/

int             Search(int alpha, int beta, int depth, MOVE * pBestMove)
{
    int             i,
                    value,
                    havemove,
               movecnt;
    MOVE            moveBuf[200],
                    tmpMove;
   
    nodes++; /* visiting a node, count it */
    havemove = 0;
    pBestMove->type = MOVE_TYPE_NONE;
   movecnt = Gen(side, moveBuf); /* generate all moves for current position */
    /* loop through the moves */
    for (i = 0; i < movecnt; ++i) {
        if (!MakeMove(moveBuf[i])) {
            TakeBack();
            continue;
        }
        havemove = 1;
        if (depth - 1 > 0) /* If depth is still, continue to search deeper */
            value = -Search(-beta, -alpha, depth - 1, &tmpMove);
        else /* If no depth left (leaf node), go to evalute that position */
            value = Eval();
        TakeBack();
        if (value > alpha) {
            /* This move is so good and caused a cutoff */
            if (value >= beta)
                return beta;
            alpha = value;
            *pBestMove = moveBuf[i]; /* so far, current move is the best reaction
                             * for current position */
        }
    }
    if (!havemove) {            /* If no legal moves, that is checkmate or
                                 * stalemate */
        if (IsInCheck(side))
            return -MATE + ply; /* add ply to find the longest path to lose or shortest path to win */
        else
            return 0;
    }
    return alpha;
}

MOVE            ComputerThink(int max_depth)
{
    MOVE            m;
    int             score;
   /* reset some values before searching */
    ply = 0;
    nodes = 0;
   /* search now */
    score = Search(-MATE, MATE, max_depth, &m);
   /* after searching, print results */
    printf("Search result: move = %c%d%c%d; nodes = %d, score = %d\n",
           'a' + COL(m.from),
           8 - ROW(m.from),
           'a' + COL(m.dest),
           8 - ROW(m.dest),
           nodes,
           score
        );
    return m;
}

/*
****************************************************************************
* Utilities                                                                *
****************************************************************************
*/
void            PrintBoard()
{
    char            pieceName[] = "PNBRQKpnbrqk";
    int             i;
    for (i = 0; i < 64; i++) {
        if ((i & 7) == 0) {
            printf("   +---+---+---+---+---+---+---+---+\n");
            if (i <= 56) {
                printf(" %d |", 8 - (((unsigned)i) >> 3));
            }
        }
        if (piece[i] == EMPTY)
            printf("   |");
        else {
            printf(" %c |", pieceName[piece[i] + (color[i] == WHITE ? 0 : 6)]);
        }
        if ((i & 7) == 7)
            printf("\n");
    }
    printf("   +---+---+---+---+---+---+---+---+\n     a   b   c   d   e   f   g   h\n");
}

/*
****************************************************************************
* Main program                                                             *
****************************************************************************
*/

void             xboard();

void         startgame()
{
   int i;
   for (i = 0; i < 64; ++i) {
      piece[i] = org_piece[i];
      color[i] = org_color[i];
   }

    side = WHITE;
    computer_side = BLACK;      /* Human is white side */
    hdp = 0;
}

void             main()
{
    char            s[256];
    int             from,
                    dest,
                    i;
    MOVE            moveBuf[200], bestMove;
    int             movecnt;
   
   printf("First Chess, by Pham Hong Nguyen\n");
    printf("Help\n d: display board\n MOVE: make a move (e.g. b1c3, a7a8q)\n quit: exit\n\n");

   startgame();
   max_depth = 5;
   
   for (;;) {
        if (side == computer_side) {    /* computer's turn */
            /* Find out the best move to react the current position */
            bestMove = ComputerThink(max_depth);
            MakeMove(bestMove);
            continue;
        }
        /* get user input */
        printf("fc> ");
        if (scanf("%s", s) == EOF) /* close program */
            return;
        if (!strcmp(s, "d")) {
            PrintBoard();
            continue;
        }
        if (!strcmp(s, "xboard")) {
         xboard();
            return;
        }
        if (!strcmp(s, "quit")) {
            printf("Good bye!\n");
            return;
        }
        /* maybe the user entered a move? */
        from = s[0] - 'a';
        from += 8 * (8 - (s[1] - '0'));
        dest = s[2] - 'a';
        dest += 8 * (8 - (s[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++)
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (s[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;

                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;

                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;

                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;

                    default:

                        puts("promoting to a McGuffin..., I'll give you a queen");
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

            }
    }
}

void             xboard()
{
    char            line[256], command[256], c;
    int             from,
                    dest,
                    i;
    MOVE            moveBuf[200], bestMove;
    int             movecnt;
   
   signal(SIGINT, SIG_IGN);
   printf("\n");
   
   startgame();

   for (;;) {
      fflush(stdout);
        if (side == computer_side) {    /* computer's turn */
            /* Find out the best move to react the current position */
            bestMove = ComputerThink(max_depth);
            MakeMove(bestMove);
         /* send move */
         switch (bestMove.type)  {
            case MOVE_TYPE_PROMOTION_TO_QUEEN:
               c = 'q';
               break;
            case MOVE_TYPE_PROMOTION_TO_ROOK:
               c = 'r';
               break;
            case MOVE_TYPE_PROMOTION_TO_BISHOP:
               c = 'b';
               break;
            case MOVE_TYPE_PROMOTION_TO_KNIGHT:
               c = 'n';
               break;
            default:
               c = ' ';
         printf("move %c%d%c%d%c\n",
            'a' + COL(bestMove.from),
            8 - ROW(bestMove.from),
            'a' + COL(bestMove.dest),
            8 - ROW(bestMove.dest),
            c);
         }
            continue;
        }

      if (!fgets(line, 256, stdin))
         return;
      if (line[0] == '\n')
         continue;
      sscanf (line, "%s", command);
        if (!strcmp(command, "xboard")) {
            continue;
      }
        if (!strcmp(command, "new")) {
         startgame();
         continue;
      }
        if (!strcmp(command, "quit")) {
            return;
        }
        if (!strcmp(command, "force")) {
              computer_side = EMPTY;
         continue;
        }
        if (!strcmp(command, "white")) {
            side = WHITE;
         computer_side = BLACK;
         continue;
        }
        if (!strcmp(command, "black")) {
            side = BLACK;
         computer_side = WHITE;
         continue;
        }
        if (!strcmp(command, "sd")) {
         sscanf (line, "sd %d", &max_depth);
         continue;
        }
        if (!strcmp(command, "go")) {
              computer_side = side;
         continue;
        }
        if (!strcmp(command, "undo")) {
         if (hdp = 0)
            continue;
         TakeBack();
         continue;
        }
        if (!strcmp(command, "remove")) {
         if (hdp <= 1)
            continue;
         TakeBack();
         TakeBack();
         continue;
        }

        /* maybe the user entered a move? */
        from = command[0] - 'a';
        from += 8 * (8 - (command[1] - '0'));
        dest = command[2] - 'a';
        dest += 8 * (8 - (command[3] - '0'));
        ply = 0;
        movecnt = Gen(side, moveBuf);
        /* loop through the moves to see if it's legal */
        for (i = 0; i < movecnt; i++)
            if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
                if (piece[from] == PAWN && (dest < 8 || dest > 55)) {   /* Promotion move? */
                    switch (command[4]) {
                    case 'q':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                        break;
                    case 'r':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
                        break;
                    case 'b':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
                        break;
                    case 'n':
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
                        break;
                    default:     
                        moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
                    }
                }
                if (!MakeMove(moveBuf[i])) {
                    TakeBack();
                    printf("Illegal move.\n");
                }
                break;

            }
    }
}

Best wishes,

Pedro Castro
User avatar
Pedro Castro
 
Posts: 180
Joined: 28 Jan 2005, 01:09
Location: Pays Basque (Spain)

Re: Beginner programmer Winboard and chess computing advice

Postby tr2 » 21 Jun 2009, 10:15

Hi Pedro

Many thanks for your very helpful & prompt reply. Thank you for adding the winboard protocol code which works well & hopefully I can now learn where I went wrong in my tries at implementing it!
Interesting that you ran it in Arena too (I will try it there!-Is it better to add UCI protocol to it to use it in Arena?).
I plan now to look at all the code in this FirstChess and to see if I can learn more from this about chess engine programming (& maybe try & add my own code to FirstChess to develop & improve it. The game I have just played with it in Winboard it was very weak (playing funny moves) and it hung up when I castled-so there is plenty more to do with this).

I see you have your own engine DanaSah which looks fine (I must check out the source code-& thanks for making it available).
Anyway your help has been great.Many thanks & best wishes to you (& best wishes to all programmers here at the forum especially those who help new inexperienced hobby programmers to develop!)
tr2
 
Posts: 12
Joined: 09 Jun 2009, 17:39

Re: Beginner programmer Winboard and chess computing advice

Postby Pedro Castro » 21 Jun 2009, 17:11

Hi tr2,

You do not need to add UCI protocol but you can improve the Xboard protocol.

The first thing you can do is try implement castle and empassant in the generator of moves, you can look in TSCP. Perhaps there is some bug in the promotion, do not remember.

Then it is interesting to add to the eval at least pst (pieces square tables) for not play always the rook after the knight (a8b8 b8a8).

You'll see that FirstChess have problems with the horizon effect, you should create a quiesce function with a generator of captures.

Try edit the alphabeta and order moves.

You can also update and print pv. You can play with time and search iterative.

DanaSah start on firstchess, so you can still recognize some parts of the program (although it is written in Spanish). The generator of move and checking if a square is under attack is faster than TSCP (mailbox), so study the code of firstchess is good.
Best wishes,

Pedro Castro
User avatar
Pedro Castro
 
Posts: 180
Joined: 28 Jan 2005, 01:09
Location: Pays Basque (Spain)

Re: Beginner programmer Winboard and chess computing advice

Postby Pablo Vazquez » 22 Jun 2009, 09:49

Hi tr2,

In search(), try changing value = Eval(); to value = -Eval();

Regards
Pablo Vazquez
 
Posts: 33
Joined: 15 Aug 2007, 15:35

Next

Return to Winboard and related Topics

Who is online

Users browsing this forum: No registered users and 34 guests