My castling code

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

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

My castling code

Post by Michael Sherwin »

This was first posted umteen years ago on either the Winboard forum or this forum, don't exactly remember. However, it was never implemented. It is now implemented in my new engine although not tested yet. The basic idea behind it is that it is self contained, i.e., needing no flags or action in make move. I'm curious if anyone can find something wrong with it. It is set up for multithreading and so it has the var "t" which is the thread index. The way it works, just considering wcancas[t], is that wcancas[t] is initially set to INFINITY. As long as wcancas[t] is greater than ply[t] then the king has not moved. If the king has not moved then wcancas[t] is automatically set at INFINITY which takes care of the case when it has just become legal again. If the king is not on E1 then the king moved two ply earlier and wcancas[t] is set to ply[t] - 2. For the rook the check needs to set wcancask to ply[t] - 2 if there is no piece on H1 or to ply[t] - 1 if H1 is occupied meaning that it was captured.

Code: Select all

  if (wcancas[t] > ply[t]) {
    wcancas[t] = INFINITY;
    if (wcancask[t] > ply[t]) {
      wcancask[t] = INFINITY;
      if (board[t][E1] == WK) {
        if (board[t][H1] == WR) {
          if (!board[t][F1] && !board[t][G1]
            && !Attacked(t, E1, BLACK) && !Attacked(t, F1, BLACK) && !Attacked(t, G1, BLACK)) {
            RecordMove(E1, G1, OO, WSHORT);
          }
        }
        else {
          if (board[t][H1] == OO) {
            wcancask[t] = ply[t] - 2;
          }
          else {
            wcancas[t]--;
          }
        }
      }
      else {
        wcancas[t] = ply[t] - 2;
      }
    }
  }
EDIT: For this sample cade the order of the if statements are slightly out of order. The check for the king on E1 should have come before the check for wcancask[t]. :oops:
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: My castling code

Post by Michael Sherwin »

I have explained this a few times before. I was born with a learning disability. My short term memory is almost non existent. I have a hard time keeping certain things in memory, like computer code, long enough. That is why I'm asking for someone to take a look at this code. Also studying others people's code like SF is near impossible for me. At least I know what my code is supposed to do giving me at least half a chance! I think this code is correct/ more correct.

Code: Select all

  if (wcancas[t] > ply[t]) {
    wcancas[t] = INFINITY;
    if (board[t][E1] == WK) {
      if (wcancask[t] > ply[t]) {
        wcancask[t] = INFINITY;
        if (board[t][H1] == WR) {
          if (!board[t][F1] && !board[t][G1]
            && !Attacked(t, E1, BLACK) && !Attacked(t, F1, BLACK) && !Attacked(t, G1, BLACK)) {
            RecordMove(E1, G1, OO, WSHORT);
          }
        }
        else {
          if (board[t][H1] == OO) {
            wcancask[t] = ply[t] - 2;
          }
          else {
            wcancask[t]--;
          }
        }
      }
    }
    else {
      wcancas[t] = ply[t] - 2;
    } 
  }
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: My castling code

Post by Michael Sherwin »

With further thought it looks like ply - 2 is a mistake. When the king or rook moves and is putback with TakeBack() castling becomes possible again. Therefore, ply - 1 is probably correct.

Code: Select all

if (wcancas[t] > ply[t]) {
    wcancas[t] = INFINITY;
    if (board[t][E1] == WK) {
      if (wcancask[t] > ply[t]) {
        wcancask[t] = INFINITY;
        if (board[t][H1] == WR) {
          if (!board[t][F1] && !board[t][G1]
            && !Attacked(t, E1, BLACK) && !Attacked(t, F1, BLACK) && !Attacked(t, G1, BLACK)) {
            RecordMove(E1, G1, OO, WSHORT);
          }
        }
        else {
          wcancask[t] = ply[t] - 1;
        }
      }
    }
    else {
      wcancas[t] = ply[t] - 1;
    } 
  }
NOTE: I'm a bit disappointed that no one has bothered to try and help with this. I'm sharing an idea that may or may not be good. But, at least I am sharing. I don't come here just to take. I have shared many ideas over the years. Some of which have made it into Stockfish and other engines. I'm a contributor. Every once in a while I need help with an idea. Especially because of my short term memory problem. I literally cannot keep many lines of code in memory. If one does not know what that is like it is like reading a line of code then a second line and not remembering the first line and so it goes 1 2, 1 2, 1 2 for as many times it takes to get to line 3 and then back to lines 1 & 2 because I can't remember. And so it goes 1 2 3, 1 2 3, 1 2 3, etc. When I came up with what was coined by someone else as Sherwin bitboards it would have never been (not that it matters) if Harold Luessen had not helped because the initialization was to large and complicated that I just could not keep enough in my memory to ever be able to write it. For SISSY bitboards the initialization was small enough and simple enough that with great difficulty I was able to write it (not that it matters). Anyway, this may be my last post in the programming forum. I've made a note and taped it to the bottom of my monitor!
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: My castling code

Post by mar »

I'm not sure I understand the idea, but what's wrong with flags?
Isn't what you propose more complicated? You'd have to manage wcancas counters when you parse FEN as well.
This way board state is coupled with game state (ply counters).
You'll need two counters, one for long and one for short castling if I'm not mistaken.

In your sample code I only see code for short castling.
I don't understand what OO in board at H1 means, you put a virtual OO piece on board after castling?

What's unclear to me is what's the benefit of what you propose, I assume it should simplify makemove and/or gain extra performance?
I don't se how it simplifies makemove because you still have to adjust the counters if a rook is captured and the king could castle before the move.
I think that your counter-based approach would also require some adjustment after the engine moves, unless ply is global relative to whole game.

I'd go with the flags idea as I find it much easier to manage, but these are just some random thoughts.
I like your new ideas and consider yours posts here interesting.
Martin Sedlak
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: My castling code

Post by Michael Sherwin »

mar wrote: Sat Apr 18, 2020 10:12 pm I'm not sure I understand the idea, but what's wrong with flags?
Isn't what you propose more complicated? You'd have to manage wcancas counters when you parse FEN as well.
This way board state is coupled with game state (ply counters).
You'll need two counters, one for long and one for short castling if I'm not mistaken.

In your sample code I only see code for short castling.
I don't understand what OO in board at H1 means, you put a virtual OO piece on board after castling?

What's unclear to me is what's the benefit of what you propose, I assume it should simplify makemove and/or gain extra performance?
I don't se how it simplifies makemove because you still have to adjust the counters if a rook is captured and the king could castle before the move.
I think that your counter-based approach would also require some adjustment after the engine moves, unless ply is global relative to whole game.

I'd go with the flags idea as I find it much easier to manage, but these are just some random thoughts.
I like your new ideas and consider yours posts here interesting.
#define OO 0, is just a convention I use because O's look like zeros and I can remember the meaning. There are 6 counters. During Load fen just set all the valid ones to INFINITY and the disabled ones to zero. If I am correct (and maybe I am not) nothing else needs to be done outside that code. One thing that I do is have two different white kings and two different black kings. One can castle and one cannot. So once castling is no longer possible in the game the king that cannot castle is put in place of the king that can and then castling does not take a single clock cycle after the change. You just reminded me about castling in my first engine Carnivor when you mentioned, "pseudo piece". In my engine Carnivor a check to see if e1, f1, g1 are attacked is not done in the castling code. Instead it puts three kings on the board for the next side's move generator and then removes two of them. Saves a lot of work. Thanks for reminding me of that, I have made a note! I'll have to incorporate that in my new engine. I removed the note on my monitor. Thanks for the kind words!!
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: My castling code

Post by Michael Sherwin »

Here is my Carnivor engine. :) (two parts)

Code: Select all

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#include <time.h>
#include <signal.h>

#define TRUE  1
#define FALSE 0

#define WHITE 0
#define BLACK 1
#define BOTH  2
#define OFF  3

#define         BISHOP          0
#define         ROOK            1
#define         QUEEN           2
#define         KNIGHT          3
#define         KING            4
#define         PAWN            5
#define         CASks           6
#define         CASqs           7
#define         COMCAS          8

#define         VACANT          1
#define         FRIEND          0
#define         ENEMY           2
#define         ILLEGAL         3

#define         LR1             0
#define         L1              1
#define         R1              2
#define         LR2             3
#define         L2              4
#define         R2              5
#define         LRE             6
#define         LE              7
#define         RE              8
#define         LRQ             9
#define         LQ              10
#define         RQ              11

#define MOVE       0
#define MOVEq      1
#define MOVEr      2
#define MOVEb      3
#define MOVEn      4
#define PDMOVE     5
#define CAPTURE    6
#define CAPTUREq   7
#define CAPTUREr   8
#define CAPTUREb   9
#define CAPTUREn   10
#define CEP        11 
#define CASTLEwk   12
#define CASTLEwq   13
#define CASTLEbk   14
#define CASTLEbq   15
#define INSwc      16
#define INSwkc     17
#define INSwqc     18
#define INSbc      19
#define INSbkc     20
#define INSbqc     21

#define inf 10002

#define EMPTY 17 

#define delete(x) piece[piece[(x)].nxt].prv=piece[(x)].prv;piece[piece[(x)].prv].nxt=piece[(x)].nxt
#define insert(x) piece[piece[(x)].nxt].prv=(x);piece[piece[(x)].prv].nxt=(x)

#define getmove() fs=tree[li].fsq;ts=tree[li].tsq;fid=brd[fs];
#define getunmv() fs=hist[rply].fsq;ts=hist[rply].tsq;fid=brd[ts];

#define evalft() hist[rply].sco=hist[rply-1].sco-pctbl[side][piece[fid].pt][fs]+ \
                 pctbl[side][piece[fid].pt][ts]
#define evalcap() hist[rply].sco-=pctbl[side^1][piece[tid].pt][ts]                 
#define evalcas(s,kf,kt,rf,rt) hist[rply].sco=hist[rply-1].sco- \
        pctbl[s][4][kf]-pctbl[s][1][rf]+pctbl[s][4][kt]+pctbl[s][1][rt]
#define evalf() hist[rply].sco=hist[rply-1].sco-pctbl[side][piece[fid].pt][fs]
#define evalt() hist[rply].sco+=pctbl[side][piece[fid].pt][ts]

#define storemove() hist[rply].fsq=fs;hist[rply].tsq=ts;hist[rply].typ=mt
#define movepiece() brd[ts]=fid;brd[fs]=EMPTY;piece[fid].ps=ts;storemove()
#define unmvpiece(x) brd[fs]=fid;piece[fid].ps=fs;brd[ts]=x 
#define queen(x,y) piece[fid].pt=x;if(side){piece[fid].pv=-y;hist[rply].sco=hist[rply].sco+100-y;} \
                             else{piece[fid].pv=y;hist[rply].sco=hist[rply].sco-100+y;}
#define unqueen() if(side){piece[fid].pt=5;piece[fid].pv=-100;} \
                       else{piece[fid].pt=5;piece[fid].pv=100;}                             
#define remove() tid=brd[ts];car[rply]=tid;delete(tid);hist[rply].sco-=piece[tid].pv;evalcap()
#define putback() tid=car[rply];insert(tid)
#define capep() ceps=(side)?ts+8:ts-8;tid=brd[ceps];brd[ceps]=EMPTY;car[rply]=tid; \
                delete(tid);hist[rply].sco=hist[rply].sco-pctbl[side^1][piece[tid].pt][ceps]-piece[tid].pv
#define uncapep() tid=car[rply];brd[piece[tid].ps]=tid;insert(tid)

#define link(x) ti->fsq=fs;ti->tsq=ts;ti->typ=(x);ti++

void initmg(void);
void initdata(void);
void drawgraf(void);
int  wmg(void);
int  bmg(void);
int  wcg(void);
int  bcg(void);         
void compute(void);
int  move(void);
void unmove(void);
void getcmd(void);
int  wsearch(int,int,int);
int  bsearch(int,int,int);
int  wlegal(void);
int  blegal(void);
int  wquiesce(int,int);
int  bquiesce(int,int);
int  wpick(void);
int  bpick(void);
int  wqpick(void);
int  bqpick(void);
int  reps(void); 
void convert(int,int);
void board();
void sortpv(void);
void bench(unsigned);

unsigned char ibrd[]=
{ 14,10,12,15,16,11, 9,13,
   5, 4, 3, 2, 1, 8, 7, 6, 
  17,17,17,17,17,17,17,17,
  17,17,17,17,17,17,17,17, 
  17,17,17,17,17,17,17,17,
  17,17,17,17,17,17,17,17,
  22,21,20,19,18,25,24,23,
  31,27,29,32,33,28,26,30 };

typedef struct
{
  int ps;
  int pv;
  int pt;
  int prv;
  int nxt;
} pieces;

pieces piece[41];

pieces ipiece[41]=
{
  { 0,   0, 0, 0, 1},
  {12, 120, 5, 0, 2},
  {11, 120, 5, 1, 3},
  {10, 100, 5, 2, 4},
  { 9, 100, 5, 3, 5},
  { 8, 100, 5, 4, 6},
  {15, 100, 5, 5, 7},
  {14, 100, 5, 6, 8},
  {13, 100, 5, 7, 9},
  { 6, 290, 3, 8,10},
  { 1, 290, 3, 9,11},
  { 5, 340, 0,10,12},
  { 2, 340, 0,11,13},
  { 7, 500, 1,12,14},
  { 0, 500, 1,13,15},
  { 3, 950, 2,14,16},
  { 4,   0, 4,15,35},
  { 0,   0, 0, 0,18},
  {52,-120, 5,17,19},
  {51,-120, 5,18,20},
  {50,-100, 5,19,21},
  {49,-100, 5,20,22},
  {48,-100, 5,21,23},
  {55,-100, 5,22,24},
  {54,-100, 5,23,25},
  {53,-100, 5,24,26},
  {62,-290, 3,25,27},
  {57,-290, 3,26,28},
  {61,-340, 0,27,29},
  {58,-340, 0,28,30},
  {63,-500, 1,29,31},
  {56,-500, 1,30,32},
  {59,-950, 2,31,33},
  {60,   0, 4,32,37},
  { 0,   0, 8, 0, 0},
  { 0,   0, 6,16,36},
  { 0,   0, 7,35,39},
  { 0,   0, 6,33,38},
  { 0,   0, 7,37,40},
  { 0,   0, 0,36,39},
  { 0,   0, 0,38,40}};


unsigned char wpwn[]=
{  0,  0,  0,  0,  0,  0,  0,  0,
  R2,LR2,LR2,LR2,LR2,LR2,LR2, L2,
  R1,LR1,LR1,LR1,LR1,LR1,LR1, L1,
  R1,LR1,LR1,LR1,LR1,LR1,LR1, L1,
  RE,LRE,LRE,LRE,LRE,LRE,LRE, LE,
  R1,LR1,LR1,LR1,LR1,LR1,LR1, L1,
  RQ,LRQ,LRQ,LRQ,LRQ,LRQ,LRQ, LQ,
   0,  0,  0,  0,  0,  0,  0,  0 };

unsigned char bpwn[]=
{  0,  0,  0,  0,  0,  0,  0,  0,
  LQ,LRQ,LRQ,LRQ,LRQ,LRQ,LRQ, RQ,
  L1,LR1,LR1,LR1,LR1,LR1,LR1, R1,
  LE,LRE,LRE,LRE,LRE,LRE,LRE, RE,
  L1,LR1,LR1,LR1,LR1,LR1,LR1, R1,
  L1,LR1,LR1,LR1,LR1,LR1,LR1, R1,
  L2,LR2,LR2,LR2,LR2,LR2,LR2, R2,
   0,  0,  0,  0,  0,  0,  0,  0 };
                
unsigned char wtrgt[]=
{ 0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  1,
  2,2,2,2,2,2,2,2,
  2,2,2,2,2,2,2,3 };

unsigned char btrgt[]=
{ 0,
  2,2,2,2,2,2,2,2,
  2,2,2,2,2,2,2,3,
  1,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0 };
unsigned char bns[1808],bnd[1808],rns[3704],rnd[3704],qns[3872],qnd[3872];
unsigned char nns[890],kns[694],wpns[360],bpns[360];
unsigned int bol[64],rol[64],qol[64],nol[64],kol[64],pol[64];
  
unsigned char brd[64];
int  away;

typedef     struct      { unsigned char fsq;
                          unsigned char tsq;
                          unsigned char typ;
                          unsigned char cep; } amove;
                          
typedef     union       { amove;
                          int umove; } pmove;

typedef     union       { int sco;
                          time_t time; } value;
                          
typedef     struct      { pmove;
                          value; } node;
                          
node                    tree[2000];

node                    hist[200];

node                    pvr[200][200];
                                                                               

signed char pctbl[2][7][64]=
{{{ 6,  0,  0,  0,  0,  0,  0,  6,
   10, 30, 12, 12, 12, 12, 30, 10,
    0, 20, 30, 12, 12, 30, 20,  0,
   16, 12, 32, 32, 32, 32, 12, 16,
    0, 30, 24, 32, 32, 24, 30,  0,
    0, 12, 30, 24, 24, 30, 12,  0,
    0, 18, 20, 20, 20, 20, 18,  0,
    6,  0,  0,  0,  0,  0,  0,  6 },
  
 {  6, 10, 12, 14, 14, 12, 10,  6,
    8, 10, 10, 16, 16, 10, 10,  8,
    6,  8, 10, 12, 12, 10,  8,  6,
    4,  6,  8, 10, 10,  8,  6,  4,
    4,  6,  8, 10, 10,  8,  6,  4,
    6,  8, 10, 12, 12, 10,  8,  6,
   20, 20, 20, 20, 20, 20, 20, 20,
   18, 18, 18, 18, 18, 18, 18, 18 },
   
 { 14, 14, 14, 14, 14, 14, 14, 14,
   14, 16, 16, 16, 16, 16, 16, 14,
   14, 16, 18, 18, 18, 18, 16, 14,
   14, 16, 18, 18, 18, 18, 16, 14,
   16, 18, 20, 20, 20, 20, 18, 16,
   16, 18, 20, 20, 20, 20, 18, 16,
   18, 20, 20, 20, 20, 20, 20, 18,
   18, 18, 18, 18, 18, 18, 18, 18 },
  
 { 0,-10, 12, 12, 12, 12,-10,  0,
   6, 12, 24, 30, 26, 24, 12,  6,
  12, 24, 30, 36, 36, 38, 24, 12,
  12, 24, 36, 40, 40, 36, 24, 12,
  12, 24, 36, 42, 42, 36, 24, 12,
  12, 24, 36, 40, 40, 36, 24, 12,
   6, 12, 24, 36, 36, 24, 12,  6,
   0,  6, 12, 12, 12, 12,  6,  0  },
   
 { 30, 60, 20,-40,  0, 20, 60, 30,
  -30,-30,-30,-30,-30,-30,-30,-30,
  -20,-20,-20,-20,-20,-20,-20,-20,
  -10,  0, 20, 20, 20, 20,  0,-10,
  -10,  0, 20, 40, 40, 20,  0,-10,
  -10,  0, 20, 20, 20, 20,  0,-10,
  -10,  0,  0,  0,  0,  0,  0,-10,
  -10,-10,-10,-10,-10,-10,-10,-10 },
  
 {  0,  0,  0,  0,  0,  0,  0,  0,
    4,  4,-24,-30,-30,  8,  8,  8,
   12,  8,  0,-10,-10,  0,  4,  6,
    8, 14, 12, 20, 20,  8,  6,  4,
   10, 16, 16, 30, 30, 12, 10,  8,
   20, 40, 40, 60, 60, 40, 40, 20,
   40, 60, 60, 80, 80, 60, 60, 40,
    0,  0,  0,  0,  0,  0,  0,  0 },
    
 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  }},
     
{{  -6,  0,  0,  0,  0,  0,  0, -6,
     0,-18,-20,-20,-20,-20,-18,  0,
     0,-12,-30,-24,-24,-30,-12,  0,
     0,-30,-24,-32,-32,-24,-30,  0,
   -16,-12,-32,-32,-32,-32,-12,-16,
     0,-20,-30,-12,-12,-30,-20,  0,
   -10,-30,-12,-12,-12,-12,-30,-10,
    -6,  0,  0,  0,  0,  0,  0, -6 },
  
 {-22,-22,-22,-22,-22,-22,-22,-22,
  -24,-24,-24,-24,-24,-24,-24,-24,
   -6, -8,-10,-12,-12,-10, -8, -6,
   -4, -6, -8,-10,-10, -8, -6, -4,
   -4, -6, -8,-10,-10, -8, -6, -4,
   -6, -8,-10,-12,-12,-10, -8, -6,
   -8,-10,-10,-22,-22,-10,-10, -8,
   -8,-10,-12,-20,-20,-12,-10, -8 },

 {-18,-18,-18,-18,-18,-18,-18,-18,
  -18,-20,-20,-20,-20,-20,-20,-18,
  -16,-18,-20,-20,-20,-20,-18,-16,
  -16,-18,-20,-20,-20,-20,-18,-16,
  -14,-16,-18,-18,-18,-18,-16,-14,
  -14,-16,-18,-18,-18,-18,-16,-14,
  -14,-16,-16,-16,-16,-16,-16,-14,
  -14,-14,-14,-14,-14,-14,-14,-14 },
  
 { 0, -6,-12,-12,-12,-12, -6,  0,
  -6,-12,-24,-36,-36,-24,-12, -6,
 -12,-24,-36,-40,-40,-36,-24,-12,
 -12,-24,-36,-42,-42,-36,-24,-12,
 -12,-24,-36,-40,-40,-36,-24,-12,
 -12,-24,-30,-36,-36,-38,-24,-12,
  -6,-12,-24,-30,-26,-24,-12, -6,
   0, 10,-12,-12,-12,-12, 10,  0 },

 { 10, 10, 10, 10, 10, 10, 10, 10,
   10,  0,  0,  0,  0,  0,  0, 10,
   10,  0,-20,-20,-20,-20,  0, 10,
   10,  0,-20,-40,-40,-20,  0, 10,
   10,  0,-20,-20,-20, -0,  0, 10,
   20, 20, 20, 20, 20, 20, 20, 20,
   30, 30, 30, 30, 30, 30, 30, 30,
  -20,-60,-20, 60,  0,-20,-60,-20 },

 {  0,  0,  0,  0,  0,  0,  0,  0,
  -40,-60,-60,-80,-80,-60,-60,-40,
  -20,-40,-40,-60,-60,-40,-40,-20,
  -10,-16,-12,-30,-30,-12, -8, -6,
   -8,-14,-16,-20,-20, -8, -6, -4,
  -12, -8,  0, 10, 10,  0, -4, -6,
   -4, -4, 24, 30, 30, -8, -8, -4,
    0,  0,  0,  0,  0,  0,  0,  0 },
    
 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}};
  
unsigned int xboard=FALSE,levm,levt,levi,cap,pro,bas,repis,pvl[200],fpv;
signed int   tmp,high=0;
unsigned int car[200],first[200],lir[200],fifty[200],m,wi=FALSE,bi=FALSE,md,maxd,z;
unsigned long x; 
unsigned int repeat,side,computer,ply,rply,fs,ts,id,fid,tid,mt,li,ptype;
unsigned int wktmp,bktmp,wkrtmp,wqrtmp,bkrtmp,bqrtmp,ceps,wcastmp,bcastmp,i,j;
unsigned int wntmp,bntmp,wcas34,bcas34,nulcas;
unsigned char cmd[20],data[256],c;
time_t st,et,at;

     
int __cdecl main(void)
{ 
  initmg();
  initdata();
  drawgraf();
//  srand(clock());
    
  maxd=12800;
  bas=64;
  pro=64;
  away=128;
  at=120000;
  repeat=TRUE;
  side=WHITE;
  computer=OFF;

  while(repeat)
  {
    if(!xboard)board();
    getcmd();
    if(computer==side || computer==BOTH) compute();
  }
  return(0);
}

void getcmd()
{
  char retry;
  int tmp;

  tmp=(side)?blegal():wlegal();
  if(!m)
  {
    if(!xboard)printf("\nCheckmate!\n");
    else if(side)
           printf("0-1 {Black mates}\n");
         else
           printf("1-0 {White mates}\n");
  }
  retry=TRUE;
  while(retry)
  {
    retry=FALSE;
    if(!xboard){printf((side)?"Black":"White");printf("%d> ",rply/2);}
    if(!fgets(data,256,stdin)){repeat=FALSE;continue;}
    if(data[0]=='\n')continue;
    sscanf(data,"%s",cmd);
    strlwr(cmd);

    if(!strcmp(cmd,"xb"))
    {
      xboard=xboard^1;
      continue;
    }

    if(!strcmp(cmd,"xboard"))
    {
      xboard=TRUE;
      signal(SIGINT,SIG_IGN);
      printf("\n");
      fflush(stdout);
      continue;
    }  
    
    if(!strcmp(cmd,"white"))
    {
      side=WHITE;
      computer=BLACK;
      continue;
    }
      
    if(!strcmp(cmd,"black"))
    {
      side=BLACK;
      computer=WHITE;
      continue;
    }
      
    if(!strcmp(cmd,"both"))
    {
      computer=BOTH;
      continue;
    }
      
    if(!strcmp(cmd,"off") || !strcmp(cmd,"force"))
    {
      computer=OFF;
      continue;
    }
      
    if(!strcmp(cmd,"go"))
    {
      computer=side;
      continue;
    }
      
    if(!strcmp(cmd,"u") || !strcmp(cmd,"undo"))
    {
      if(rply<3)continue;
      computer=OFF;
      unmove();
      ply=0;
      high=0;
      continue;
    }

    if(!strcmp(cmd,"r") || !strcmp(cmd,"remove"))
    {
      if(rply<3)continue;
      unmove();
      unmove();
      ply=0;
      high=0;
      continue;
    }
      
    if(!strcmp(cmd,"new"))
    {
      for(i=rply;i>2;i--)unmove();
      initdata();
      computer=BLACK;
      side=WHITE;
      high=0;
      continue;
    }
      
    if(!strcmp(cmd,"quit"))
    {
      repeat=FALSE;
      continue;
    }

    if(!strcmp(cmd,"sa"))
    {
      sscanf(data,"sa %d",&away);
      away=away<<6;
      continue;
    }

    if(!strcmp(cmd,"sb"))
    {
      sscanf(data,"sb %d",&bas);
      continue;
    }

    if(!strcmp(cmd,"sp"))
    {
      sscanf(data,"sp %d",&pro);
      continue;
    }

    if(!strcmp(cmd,"sd"))
    {  
      sscanf(data,"sd %d",&maxd);
      maxd=maxd*64;
      at=10000000;
      continue;
    }

    if(!strcmp(cmd,"st"))
    {  
      sscanf(data,"st %lu",&at);
      at=at*(CLOCKS_PER_SEC/2);
      maxd=12800;
      continue;
    }
    
    if(!strcmp(cmd,"time"))
    {
      sscanf(data,"time %d",&at);
      at=at*4/levm;
      maxd=12800;
      continue;
    }

    if(!strcmp(cmd,"level"))
    {
      sscanf(data,"level %d %d %d",&levm,&levt,&levi);
      continue;
    }
    
    if(!strcmp(cmd,"bench"))
    {
      sscanf(data,"bench %d",&i);
      z=0;
      st=clock();
      bench(i);
      et=clock();
      printf("nodes=%d  time=%d\n",z,(int)(et-st));
      printf("nodes/sec = %d\n",(int)((float)((float)z/(float)((et-st)/(float)1000))));
      continue;
    }
       
     
    retry=TRUE;
    if(!m)continue;
    fs=cmd[0] - 'a' + 8 * (cmd[1] - '1');
    ts=cmd[2] - 'a' + 8 * (cmd[3] - '1');
    for(li=first[0];li<first[1];li++)
      if(tree[li].fsq==fs && tree[li].tsq==ts)
      { retry=FALSE;
        if(tree[li].typ==MOVEq)  
        { switch(cmd[4])
          { case 'b':tree[li].typ=MOVEb;break;
            case 'n':tree[li].typ=MOVEn;break;
            case 'q':break;
            case 'r':tree[li].typ=MOVEr;break;
            default:
                  printf("You must enter q,r,b or n when promoting\n");              
                  retry=TRUE;
          }
        }
        else
        if(tree[li].typ==CAPTUREq)  
        { switch(cmd[4])
          { case 'b':tree[li].typ=CAPTUREb;break;
            case 'n':tree[li].typ=CAPTUREn;break;
            case 'q':break;
            case 'r':tree[li].typ=CAPTUREr;break;
            default:
              printf("You must enter q,r,b or n when promoting\n");              
              retry=TRUE;
          }
        }
             
        break;  
      }
      if(retry==FALSE){lir[rply]=li;move();ply=0;}
      else {printf("Error (Unknown command): %s\n",cmd);fflush(stdout);}
      break;
  }
  return;
}

void bench(unsigned depth)
{
  if(depth<1)return;
  if(side)
  {
    if(!bmg())return;
    while(move())
    {
      z++;
      bench(depth-1);
      unmove();
    }
  }
  else
  {
    if(!wmg())return;
    while(move())
    {
      z++;
      bench(depth-1);
      unmove();
    }
  }
}

void compute(void)
{
  int best,alpha,beta;
  float sec;
  unsigned ptr,k;

  if(!xboard)printf("Ok I'm thinking.\n");
  (side)?blegal():wlegal();
  if(!m)
  {
    computer=OFF;
    if(side)
      printf("0-1 {Black mates}\n");
    else
      printf("1-0 {White mates}\n");
    return;
  }
  x=0;
  st=clock();
  memset(pvr,0,sizeof(pvr));
  alpha=-inf;beta=inf;
  for(md=bas,i=1;md<=maxd;md+=pro,i++)
  {
    ply=0;fpv=TRUE;
    (side)?bsearch(alpha,beta,md):wsearch(alpha,beta,md);
    if(!xboard)printf("\n");
    best=(side)?inf:-inf;
    for(li=first[0];li<first[1];li++)
    {
      if(side)
      {
        if(tree[li].sco<best){best=tree[li].sco;ptr=li;}
      }
      else if(tree[li].sco>best){best=tree[li].sco;ptr=li;}
    }
    fs=tree[ptr].fsq;
    ts=tree[ptr].tsq;
    convert(fs,ts);
    et=clock();
    if(best>9999)sprintf(cmd,"White MATES!");
    if(best<-9999)sprintf(cmd,"Black MATES!");
    if(!xboard)
    {
      printf("%3d   %9d  %6d ",i,x,best);
      for(k=0;k<pvl[0];k++)
      {
        fs=pvr[0][k].fsq;
        ts=pvr[0][k].tsq;
        convert(fs,ts);
        printf(" %s",cmd);
      }
      printf("\n");
    }
    else
    {
      printf("%d %d %d %d",i,best,(et-st)/CLOCKS_PER_SEC,x);
      for(k=0;k<pvl[0];k++)
      {
        fs=pvr[0][k].fsq;
        ts=pvr[0][k].tsq;
        convert(fs,ts);
        printf(" %s",cmd);
      }
      printf("\n");
      fflush(stdout);
    }  
    if(et-st > at || ((best>9000 || best<-9000) && abs(best)>high))break;
  }
  et=clock();et=(et-st);sec=(float)et/CLOCKS_PER_SEC;if(sec<.001)sec=(float).001;
  if(side)while(bpick() && move())unmove();else while(wpick() && move())unmove();
  best=(side)?inf:-inf;
  for(li=first[0];li<first[1];li++)
  {
    if(side)
    {
      if(tree[li].sco<best){best=tree[li].sco;lir[rply]=li;}
    }
    else if(tree[li].sco>best){best=tree[li].sco;lir[rply]=li;}  
  }
  if(abs(best)>high)high=best;
  move();
  convert(fs,ts);
  if(best>9999 || best<-9999)
  {
    printf("move %s\n",cmd);
    printf("\ncheckmate\n");
    fflush(stdout);
    computer=OFF;
    return;
  }
  ply=0;
  if(!xboard)
  {
    printf("\n\nMy move is %s score=%d Nodes=%lu Sec.=%.2f n/s=%lu\n\n"
      ,cmd,tree[li].sco,x,(float)sec,(long)((float)x/sec));
  }
  else
  {
    printf("move %s\n",cmd);
    fflush(stdout);
  }
}

int wsearch(int alpha,int beta,int depth)
{
  unsigned int sli;
  int s,ka,n;

  pvl[ply]=ply;
  
  if(depth<1)// return wquiesce(alpha,beta);
  {
    s=wquiesce(alpha,beta);
    if(s>=alpha && s<=beta && ply<i)depth=1;
    else return s;
  }

  if(ply)
  {
//    if(reps())return 0;
    if(!wmg())return inf-ply;
  }
  if(depth>=64)
  {
    nulcas=piece[33].nxt;piece[33].nxt=40;
    side=1^side;ply++;rply++;
    s=bquiesce(alpha,beta);
    side=1^side;ply--;rply--;
    piece[33].nxt=nulcas;
    if(s+50>=beta) depth-=(128+(ply<<2));
    else
    {
      ka=FALSE;
      if(s<-9000){ka=TRUE;depth+=(128-(ply<<3));}
      else if(s<alpha)depth+=(64-(ply<<3));
    }
  }
  
  if(ply)
  {
    while(move())
    {
      tree[li].sco=hist[rply-1].sco;
      unmove();
    }
    
    if(depth>384)
    {
      while(wpick() && move())
      {
        sli=li;
        tree[sli].sco=bquiesce(-inf,beta);
        unmove();
      }
    }
  }        
  
  n=0;
  while(wpick() && move())
  {
    if(ply==1){if(!xboard)printf(".");}
    sli=li;
    tree[sli].sco=bsearch(alpha,beta,depth-64);
    unmove();
    if(tree[sli].sco>=beta)return tree[sli].sco;
    if(tree[sli].sco>alpha)
    {
      alpha=tree[sli].sco;
      pvr[ply][ply].umove=tree[sli].umove;
      for(j=ply+1;j<pvl[ply+1];j++)pvr[ply][j]=pvr[ply+1][j];
      pvl[ply]=pvl[ply+1];
    }
    if(tree[sli].sco>(signed)(-10001+ply))n++;
  }
  if(!n && !ka)return 0;
//  if(fifty[rply-1]==100)return 0;
  return alpha;
}    

int bsearch(int alpha,int beta,int depth)
{
  unsigned int sli;
  int s,ka,n;

  pvl[ply]=ply;
  
  if(depth<1)// return bquiesce(alpha,beta);
  {
    s=bquiesce(alpha,beta);
    if(s>=alpha && s<=beta && ply<i)depth=1;
    else return s;
  }
     
  if(ply)
  {
//    if(reps())return 0;
    if(!bmg())return -inf+ply;
  }

  if(depth>=64)
  {
    nulcas=piece[16].nxt;piece[16].nxt=39;
    side=1^side;ply++;rply++;
    s=wquiesce(alpha,beta);
    side=1^side;ply--;rply--;
    piece[16].nxt=nulcas;
    if(s-50<=alpha) depth-=(128+(ply<<2));
    else
    {
      ka=FALSE;
      if(s>9000){ka=TRUE;depth+=(128-(ply<<3));}
      else if(s>beta)depth+=(64-(ply<<3));
    }
  }
  if(ply)
  {
    while(move())
    {
      tree[li].sco=hist[rply-1].sco;
      unmove();
    }
    
    if(depth>384)
    { 
      while(bpick() && move())
      {
        sli=li;
        tree[sli].sco=wquiesce(alpha,inf);
        unmove();
      }
    }
  }        

  n=0;
  while(bpick() && move())
  {
    if(ply==1){if(!xboard)printf(".");}
    sli=li;
    tree[sli].sco=wsearch(alpha,beta,depth-64);
    unmove();
    if(tree[sli].sco<=alpha)return tree[sli].sco;
    if(tree[sli].sco<beta)
    {
      beta=tree[sli].sco;
      pvr[ply][ply].umove=tree[sli].umove;
      for(j=ply+1;j<pvl[ply+1];j++)pvr[ply][j]=pvr[ply+1][j];
      pvl[ply]=pvl[ply+1];
    }
    if(tree[sli].sco<(signed)(10001-ply))n++;
  }
  if(!n && !ka)return 0;
//  if(fifty[rply-1]==100)return 0;
  return beta;
}    
      
int wlegal()
{ 
  unsigned int sli;
  int alpha=-inf;
        
  if(!wmg())return FALSE;
  while(move())
  {
    tree[li].sco=hist[rply-1].sco;
    unmove();
  }
  m=0;
  while(wpick() && move())
  { 
    m++;
    sli=li;
    tree[sli].sco=bquiesce(-inf,inf);
    unmove();
    if(tree[sli].sco==-inf+1)
    {
      m--;
      first[ply+1]--;
      li=first[ply+1];
      if(li==sli)continue;
      tree[sli].fsq=tree[li].fsq;tree[sli].tsq=tree[li].tsq;tree[sli].typ=tree[li].typ;
      lir[rply]--;continue;
    }
    if(tree[sli].sco>alpha)alpha=tree[sli].sco;  
  }
  return alpha;
}


int blegal()
{ 
  unsigned int sli;
  int beta=inf;
        
  if(!bmg())return FALSE;
  while(move())
  {
    tree[li].sco=hist[rply-1].sco;
    unmove();
  }
  m=0;
  while(bpick() && move())
  { 
    m++;
    sli=li;
    tree[sli].sco=wquiesce(-inf,inf);
    unmove();
    if(tree[sli].sco==inf-1)
    {
      m--;
      first[ply+1]--;
      li=first[ply+1];
      if(li==sli)continue;
      tree[sli].fsq=tree[li].fsq;tree[sli].tsq=tree[li].tsq;tree[sli].typ=tree[li].typ;
      lir[rply]--;continue;
    }
    if(tree[sli].sco<beta)beta=tree[sli].sco;  
  }
  return beta;
}

int wquiesce(int alpha,int beta)
{
  signed int s;

  s=hist[rply-1].sco;
  if(s>=beta)return s;
  if(s>alpha)alpha=s;
  if(!wcg())return inf-ply;
  if(first[ply]==first[ply+1])return alpha;

  while(move())
  {
    tree[li].sco=hist[rply-1].sco;
    unmove();
  }
 
  while(wpick() && move())
  {
    if(hist[rply-1].sco<alpha){unmove();return hist[rply-1].sco;} 
    s=bquiesce(alpha,beta);
    unmove();
    if(s>=beta)return s;
    if(s>alpha)alpha=s;
  }
  return alpha;
}
  
int bquiesce(int alpha,int beta)
{
  int s;
  
  s=hist[rply-1].sco;
  if(s<=alpha)return s;
  if(s<beta)beta=s;
  if(!bcg())return -inf+ply;
  if(first[ply]==first[ply+1])return beta;

  while(move())
  {
    tree[li].sco=hist[rply-1].sco;
    unmove();
  }

  while(bpick() && move())
  {
    if(hist[rply-1].sco>beta){unmove();return hist[rply-1].sco;}
    s=wquiesce(alpha,beta);
    unmove();
    if(s<=alpha)return s;
    if(s<beta)beta=s;
  }
  return beta;
}

int reps()
{
  unsigned i;
  int b[64];
  int c=0;
//  int r=0;

  if(fifty[rply-1]<=3)return 0;

  memset(b,0,sizeof(b));

  for(i=rply-1;i>=rply-fifty[rply-1]-1;--i)
  {
    if(++b[hist[i].fsq]==0)--c;
    else ++c;
    if(--b[hist[i].tsq]==0)--c;
    else ++c;
    if(c==0)return 1;
  }
  return 0;
}

void sortpv()
{
  unsigned i;
  
  fpv=FALSE;
  for(i=first[ply];i<first[ply+1];i++)
    if(tree[i].umove==pvr[0][ply].umove)
    {
      fpv=TRUE;
      tree[i].sco=(side)?-100000:100000;
      return;
    }
}

int wpick()
{
  register signed int best=-20000;
  register unsigned int ptr,sli;
  register unsigned tmp;

  li=lir[rply];
  if(li==first[ply+1]-1)return TRUE;
  if(li>=first[ply+1]){lir[rply]=first[ply];return FALSE;}
  for(sli=li;sli<first[ply+1];sli++)
   if(tree[sli].sco>best){best=tree[sli].sco;ptr=sli;}
  if(li!=ptr)
  { tmp=tree[ptr].umove;tree[ptr].umove=tree[li].umove;tree[li].umove=tmp;
    tree[ptr].sco=tree[li].sco;tree[li].sco=best;
  }
  return TRUE;
}    
      
int bpick()
{
  register signed int best=20000;
  register unsigned int ptr,sli;
  register unsigned tmp;

  li=lir[rply];
  if(li==first[ply+1]-1)return TRUE;
  if(li>=first[ply+1]){lir[rply]=first[ply];return FALSE;}
  for(sli=li;sli<first[ply+1];sli++)
   if(tree[sli].sco<best){best=tree[sli].sco;ptr=sli;}
  if(li!=ptr)
  { tmp=tree[ptr].umove;tree[ptr].umove=tree[li].umove;tree[li].umove=tmp;
    tree[ptr].sco=tree[li].sco;tree[li].sco=best;
  }
  return TRUE;
}    

int wmg()
{
  char *sbns,*sbnd;
  node *ti;
  int fs,ts;
  
  ti=tree+first[ply];
  for(id=piece[0].nxt;id<39;id=piece[id].nxt)
  {
    fs=piece[id].ps;
    switch(piece[id].pt)
    {
      case BISHOP:
             sbns=bns+bol[fs];
             sbnd=bnd+bol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }
             continue;
             
      case ROOK:
             sbns=rns+rol[fs];
             sbnd=rnd+rol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case QUEEN:
             sbns=qns+qol[fs];
             sbnd=qnd+qol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case KNIGHT:
             sbns=nns+nol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbns+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbns+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case KING:
             sbns=kns+kol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbns+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbns+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case PAWN:
             switch(wpwn[fs])
             {
               case LR1:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case L1:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case R1:
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case LR2:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs+8]==EMPTY)
                      {
                               link(MOVE);
                               if(brd[ts=fs+16]==EMPTY)
                               {link(PDMOVE);}
                      }         
                      continue;
               case L2:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs+8]==EMPTY)
                      {
                               link(MOVE);
                               if(brd[ts=fs+16]==EMPTY)
                               {link(PDMOVE);}
                      }         
                      continue;
               case R2:
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs+8]==EMPTY)
                      {
                               link(MOVE);
                               if(brd[ts=fs+16]==EMPTY)
                               {link(PDMOVE);}
                      }         
                      continue;
               case LRE:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case LE:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case RE:
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs+8]==EMPTY)
                              {link(MOVE);}
                      continue;
               case LRQ:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVEq);}
                      continue;
               case LQ:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVEq);}
                      continue;
               case RQ:
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                              {link(MOVEq);}
                      continue;         
             }
             continue;
      case CASks:                       
             if(brd[4]==16)
             { if(brd[7]==13)
               { if(brd[5]==EMPTY && brd[6]==EMPTY)
                 { ti->typ=CASTLEwk;ti->fsq=4;ti->tsq=6;ti++;}}
               else
               { wkrtmp=hist[rply-1].typ;hist[rply-1].typ=INSwkc;delete(35);}}    
             else
             { wktmp=hist[rply-1].typ;hist[rply-1].typ=INSwc;wntmp=piece[16].nxt;piece[16].nxt=39;id=39;}  
             continue;
      case CASqs:
             if(brd[4]==16)
             { if(brd[0]==14)
               { if(brd[3]==EMPTY && brd[2]==EMPTY && brd[1]==EMPTY)
                 { ti->typ=CASTLEwq;ti->fsq=4;ti->tsq=2;ti++;}}
               else
               { wqrtmp=hist[rply-1].typ;hist[rply-1].typ=INSwqc;delete(36);}}    
             else
             { wktmp=hist[rply-1].typ;hist[rply-1].typ=INSwc;wntmp=piece[16].nxt;piece[16].nxt=39;id=39;}  
             continue;
      default:
             switch(hist[rply-1].typ)
             {
               case CASTLEbk:brd[60]=EMPTY;brd[61]=30;piece[33].ps=62;piece[30].ps=61;piece[16].nxt=wcas34;
                           id=16;bcastmp=piece[33].nxt;piece[33].nxt=40;
                           continue;
               case CASTLEbq:brd[60]=EMPTY;brd[59]=31;piece[33].ps=58;piece[31].ps=59;piece[16].nxt=wcas34;
                           id=16;bcastmp=piece[33].nxt;piece[33].nxt=40;
                           continue;
             }      
             continue;
     }
  }
  first[ply+1]=ti-tree;
  lir[rply]=first[ply];
  return TRUE;
}
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: My castling code

Post by Michael Sherwin »

Code: Select all

int bmg()
{
  char *sbns,*sbnd;
  node *ti;
  int fs,ts;
  
  ti=tree+first[ply];
  for(id=piece[17].nxt;id<40;id=piece[id].nxt)
  {
    fs=piece[id].ps;
    switch(piece[id].pt)
    {
      case BISHOP:
             sbns=bns+bol[fs];
             sbnd=bnd+bol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case ROOK:
             sbns=rns+rol[fs];
             sbnd=rnd+rol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case QUEEN:
             sbns=qns+qol[fs];
             sbnd=qnd+qol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case KNIGHT:
             sbns=nns+nol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbns+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbns+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case KING:
             sbns=kns+kol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        link(MOVE);
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbns+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbns+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case PAWN:
             switch(bpwn[fs])
             {
               case LR1:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case L1:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case R1:
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case LR2:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs-8]==EMPTY)
                      {
                               link(MOVE);
                               if(brd[ts=fs-16]==EMPTY)
                               {link(PDMOVE);}
                      }         
                      continue;
               case L2:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs-8]==EMPTY)
                      {
                               link(MOVE);
                               if(brd[ts=fs-16]==EMPTY)
                               {link(PDMOVE);}
                      }         
                      continue;
               case R2:
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs-8]==EMPTY)
                      {
                               link(MOVE);
                               if(brd[ts=fs-16]==EMPTY)
                               {link(PDMOVE);}
                      }         
                      continue;
               case LRE:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case LE:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case RE:
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVE);}
                      continue;
               case LRQ:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVEq);}
                      continue;
               case LQ:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVEq);}
                      continue;
               default:
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVEq);}
                      continue;         
             }
             continue;
      case CASks:
             if(brd[60]==33)
             { if(brd[63]==30)
               { if(brd[61]==EMPTY && brd[62]==EMPTY)
                 { ti->typ=CASTLEbk;ti->fsq=60;ti->tsq=62;ti++;}}
               else
               { bkrtmp=hist[rply-1].typ;hist[rply-1].typ=INSbkc;delete(37);}}    
             else
             { bktmp=hist[rply-1].typ;hist[rply-1].typ=INSbc;bntmp=piece[33].nxt;piece[33].nxt=40;id=40;}  
             continue;
      case CASqs:
             if(brd[60]==33)
             { if(brd[56]==31)
               { if(brd[59]==EMPTY && brd[58]==EMPTY && brd[57]==EMPTY)
                 { ti->typ=CASTLEbq;ti->fsq=60;ti->tsq=58;ti++;}}
               else
               { bqrtmp=hist[rply-1].typ;hist[rply-1].typ=INSbqc;delete(38);}}    
             else
             { bktmp=hist[rply-1].typ;hist[rply-1].typ=INSbc;bntmp=piece[33].nxt;piece[33].nxt=40;id=40;}  
             continue;
      default:
             switch(hist[rply-1].typ)
             { case CASTLEwk:brd[4]=EMPTY;brd[5]=13;piece[16].ps=6;piece[13].ps=5;piece[33].nxt=bcas34;
                           id=33;wcastmp=piece[16].nxt;piece[16].nxt=39;
                           continue;
               case CASTLEwq:brd[4]=EMPTY;brd[3]=14;piece[16].ps=2;piece[14].ps=3;piece[33].nxt=bcas34;
                           id=33;wcastmp=piece[16].nxt;piece[16].nxt=39;
                           continue;
             }      
             continue;
    }
  }
  first[ply+1]=ti-tree;
  lir[rply]=first[ply];
  return TRUE;
}

int wcg()
{
  char *sbns,*sbnd;
  node *ti;
  int fs,ts;
  
  ti=tree+first[ply];
  for(id=piece[0].nxt;id<=34;id=piece[id].nxt)
  {
    fs=piece[id].ps;
    switch(piece[id].pt)
    {
      case BISHOP:
             sbns=bns+bol[fs];
             sbnd=bnd+bol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case ROOK:
             sbns=rns+rol[fs];
             sbnd=rnd+rol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case QUEEN:
             sbns=qns+qol[fs];
             sbnd=qnd+qol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case KNIGHT:
             sbns=nns+nol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbns+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbns+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case KING:
             sbns=kns+kol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(wtrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbns+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbns+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case PAWN:
             switch(wpwn[fs])
             {
               case LR1:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      continue;
               case L1:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      continue;
               case R1:
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      continue;
               case LR2:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      continue;                
               case L2:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case R2:
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                     continue;
               case LRE:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               continue;
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case LE:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               continue;
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case RE:
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               continue;
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case LRQ:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVEq);}
                      continue;
               case LQ:
                      switch(wtrgt[brd[ts=fs+7]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVEq);}
                      continue;
               default:
                      switch(wtrgt[brd[ts=fs+9]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs+8]==EMPTY)
                               {link(MOVEq);}
                      continue;         
             }
             continue;
      default:
             switch(hist[rply-1].typ)
             {
               case CASTLEbk:brd[60]=EMPTY;brd[61]=30;piece[33].ps=62;piece[30].ps=61;piece[16].nxt=wcas34;
                           id=16;bcastmp=piece[33].nxt;piece[33].nxt=40;
                           continue;
               case CASTLEbq:brd[60]=EMPTY;brd[59]=31;piece[33].ps=58;piece[31].ps=59;piece[16].nxt=wcas34;
                           id=16;bcastmp=piece[33].nxt;piece[33].nxt=40;
                           continue;
             }      
             continue;
     }
  }
  first[ply+1]=ti-tree;
  lir[rply]=first[ply];
  return TRUE;
}

int bcg()
{
  char *sbns,*sbnd;
  node *ti;
  int fs,ts;
  
  ti=tree+first[ply];
  for(id=piece[17].nxt;id<=34;id=piece[id].nxt)
  {
    fs=piece[id].ps;
    switch(piece[id].pt)
    {
      case BISHOP:
             sbns=bns+bol[fs];
             sbnd=bnd+bol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case ROOK:
             sbns=rns+rol[fs];
             sbnd=rnd+rol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case QUEEN:
             sbns=qns+qol[fs];
             sbnd=qnd+qol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbnd+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbnd+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case KNIGHT:
             sbns=nns+nol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbns+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbns+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case KING:
             sbns=kns+kol[fs];
             ts=*(sbns+fs);
             while(ts<64)
             {
               switch(btrgt[brd[ts]])
               {
                 case VACANT:
                        ts=*(sbns+ts);
                        continue;
                 case FRIEND:             
                        ts=*(sbns+ts);
                        continue;
                 case ENEMY:
                        link(CAPTURE);
                        ts=*(sbns+ts);
                        continue;
                 default:
                        return FALSE;
               }                            
             }  
             continue;
             
      case PAWN:
             switch(bpwn[fs])
             {
               case LR1:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      continue;
               case L1:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }
                     continue;
               case R1:
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }
                     continue;
               case LR2:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case L2:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case R2:
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                     continue;
               case LRE:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               break;
                        case ENEMY:
                               link(CAPTURE);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               continue;
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case LE:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               continue;
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case RE:
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case VACANT:
                               if(ts==hist[rply].cep)
                               {link(CEP);}
                               continue;
                        case ENEMY:
                               link(CAPTURE);
                               continue;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      continue;
               case LRQ:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }                
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVEq);}
                      continue;
               case LQ:
                      switch(btrgt[brd[ts=fs-7]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVEq);}
                      continue;
               default:
                      switch(btrgt[brd[ts=fs-9]])
                      {
                        case ENEMY:
                               link(CAPTUREq);
                               break;
                        case ILLEGAL:
                               return FALSE;              
                      }
                      if(brd[ts=fs-8]==EMPTY)
                               {link(MOVEq);}
                      continue;         
             }
             continue;
      default:
             switch(hist[rply-1].typ)
             { case CASTLEwk:brd[4]=EMPTY;brd[5]=13;piece[16].ps=6;piece[13].ps=5;piece[33].nxt=bcas34;
                           id=33;wcastmp=piece[16].nxt;piece[16].nxt=39;
                           continue;
               case CASTLEwq:brd[4]=EMPTY;brd[3]=14;piece[16].ps=2;piece[14].ps=3;piece[33].nxt=bcas34;
                           id=33;wcastmp=piece[16].nxt;piece[16].nxt=39;
                           continue;
             }      
             continue;
    }
  }
  first[ply+1]=ti-tree;
  lir[rply]=first[ply];
  return TRUE;
}

int move(void)
{ 
  li=lir[rply];
  if(li>=first[ply+1]){lir[rply]=first[ply];return FALSE;}  
  mt=tree[li].typ;
  switch(mt)
  { case MOVE:getmove();movepiece();evalft();if(piece[id].pt!=5)fifty[rply]=fifty[rply-1]+1;
                                             else fifty[rply]=0;
     break;           
    case MOVEq:getmove();movepiece();evalf();queen(2,950);evalt();fifty[rply]=0;
     break;
    case MOVEr:getmove();movepiece();evalf();queen(1,500);evalt();fifty[rply]=0;
     break;
    case MOVEb:getmove();movepiece();evalf();queen(0,320);evalt();fifty[rply]=0;
     break;
    case MOVEn:getmove();movepiece();evalf();queen(3,290);evalt();fifty[rply]=0;
     break;
    case PDMOVE:getmove();movepiece();evalft();hist[rply+1].cep=(side)?fs-8:fs+8;
                fifty[rply]=0;
     break;
    case CAPTURE:getmove();evalft();remove();movepiece();fifty[rply]=0;
     break;
    case CAPTUREq:getmove();evalf();remove();movepiece();queen(2,950);evalt();fifty[rply]=0;
     break;
    case CAPTUREr:getmove();evalf();remove();movepiece();queen(1,500);evalt();fifty[rply]=0;
     break;
    case CAPTUREb:getmove();evalf();remove();movepiece();queen(0,320);evalt();fifty[rply]=0;
     break;
    case CAPTUREn:getmove();evalf();remove();movepiece();queen(3,290);evalt();fifty[rply]=0;
     break;      
    case CEP:getmove();
             evalft();
             capep();
             movepiece();
             fifty[rply]=0;
     break;
    case CASTLEwk: brd[7]=EMPTY;brd[6]=16;brd[5]=16;bcas34=piece[33].nxt;
                   piece[33].nxt=34;hist[rply].typ=CASTLEwk;evalcas(0,4,6,7,5);
                   fs=4;ts=6;fifty[rply]=0;                
     break;  
    case CASTLEwq: brd[0]=EMPTY;brd[2]=16;brd[3]=16;bcas34=piece[33].nxt;
                   piece[33].nxt=34;hist[rply].typ=CASTLEwq;evalcas(0,4,2,0,3);
                   fs=4;ts=2;fifty[rply]=0;                
     break;  
    case CASTLEbk: brd[63]=EMPTY;brd[62]=33;brd[61]=33;wcas34=piece[16].nxt;
                   piece[16].nxt=34;hist[rply].typ=CASTLEbk;evalcas(1,60,62,63,61);
                   fs=60;ts=62;fifty[rply]=0;              
     break;  
    case CASTLEbq: brd[56]=EMPTY;brd[58]=33;brd[59]=33;wcas34=piece[16].nxt;
                   piece[16].nxt=34;hist[rply].typ=CASTLEbq;evalcas(1,60,58,56,59);
                   fs=60;ts=58;fifty[rply]=0;                
     break;  
  }
  lir[rply]++;rply++;ply++;x++;side=1^side;
  return TRUE;
}

void unmove(void)
{ 
  side=1^side;  
  rply--;ply--;
  mt=hist[rply].typ;
um1:
  switch(mt)
  { case MOVE:getunmv();unmvpiece(EMPTY);
     break;  
    case MOVEq:getunmv();
    unqueen();
    unmvpiece(EMPTY);
     break; 
    case MOVEr:getunmv();unqueen();unmvpiece(EMPTY);
     break;  
    case MOVEb:getunmv();unqueen();unmvpiece(EMPTY);
     break;   
    case MOVEn:getunmv();unqueen();unmvpiece(EMPTY);
     break;  
    case PDMOVE:getunmv();unmvpiece(EMPTY);hist[rply+1].cep=0;
     break;
    case CAPTURE:getunmv();
    putback();
    unmvpiece(tid);
     break; 
    case CAPTUREq:getunmv();putback();unqueen();unmvpiece(tid);
     break; 
    case CAPTUREr:getunmv();putback();unqueen();unmvpiece(tid);
     break;   
    case CAPTUREb:getunmv();putback();unqueen();unmvpiece(tid);
     break;   
    case CAPTUREn:getunmv();putback();unqueen();unmvpiece(tid);
     break;   
    case CEP:getunmv();uncapep();unmvpiece(EMPTY);
     break;
    case CASTLEwk: brd[4]=16;brd[5]=EMPTY;brd[6]=EMPTY;brd[7]=13;piece[16].ps=4;piece[13].ps=7;
                          if(piece[33].nxt==34)piece[33].nxt=bcas34;else piece[16].nxt=wcastmp;
     break;
    case CASTLEwq: brd[4]=16;brd[3]=EMPTY;brd[2]=EMPTY;brd[0]=14;piece[16].ps=4;piece[14].ps=0;
                          if(piece[33].nxt==34)piece[33].nxt=bcas34;else piece[16].nxt=wcastmp;
     break;
    case CASTLEbk: brd[60]=33;brd[61]=EMPTY;brd[62]=EMPTY;brd[63]=30;piece[33].ps=60;piece[30].ps=63;
                          if(piece[16].nxt==34)piece[16].nxt=wcas34;else piece[33].nxt=bcastmp;
     break;
    case CASTLEbq: brd[60]=33;brd[59]=EMPTY;brd[58]=EMPTY;brd[56]=31;piece[33].ps=60;piece[31].ps=56;
                          if(piece[16].nxt==34)piece[16].nxt=wcas34;else piece[33].nxt=bcastmp;
     break;
    case INSwc:  piece[16].nxt=wntmp;mt=wktmp;
     goto um1;
    case INSwkc: insert(35);mt=wkrtmp;
     goto um1;
    case INSwqc: insert(36);mt=wqrtmp;
     goto um1;
    case INSbc:  piece[33].nxt=bntmp;mt=bktmp;
     goto um1;
    case INSbkc: insert(37);mt=bkrtmp;
     goto um1;
    case INSbqc: insert(38);mt=bqrtmp;
     goto um1;
  }  
}
        
void initmg(void)
{
  signed char lbrd [120] =
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
     -1,0,1,2,3,4,5,6,7,-1,
     -1,8,9,10,11,12,13,14,15,-1,
     -1,16,17,18,19,20,21,22,23,-1,
     -1,24,25,26,27,28,29,30,31,-1,
     -1,32,33,34,35,36,37,38,39,-1,
     -1,40,41,42,43,44,45,46,47,-1,
     -1,48,49,50,51,52,53,54,55,-1,
     -1,56,57,58,59,60,61,62,63,-1,
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

  signed char pdir [7] [8] =
    {{9,11,-9,-11,0,0,0,0},
     {1,10,-1,-10,0,0,0,0},
     {9,11,1,10,-9,-11,-1,-10},
     {8,12,19,21,-8,-12,-19,-21},
     {9,11,1,10,-9,-11,-1,-10},
     {10,9,11,0,0,0,0,0},
     {-10,-9,-11,0,0,0,0,0}};

  unsigned char maxs [7] =
    {6,6,6,0,0,0,0};

  unsigned char maxdir [7] =
    {3,3,7,7,7,2,2};

  signed char min=64,max=0;
  signed char ptyp;
  signed char plfs,lds,lts;
  signed char fs,ts,nds,pfs;
  signed char dir,ndir,ppdir,s;
  unsigned char *sbns,*sbnd;
  unsigned int *pop;
  signed int offset=0;

  for(ptyp=0;ptyp<6;ptyp++)
    {
      switch (ptyp)
        {
        case 0:
          pop=bol;
          break;
        case 1:
          pop=rol;
          break;
        case 2:
          pop=qol;
          break;
        case 3:
          pop=nol;
          break;
        case 4:
          pop=kol;
          break;
        case 5:
          pop=pol;
          offset=8;
        }
      for(plfs=21;plfs<99;plfs++)
        if((pfs=fs=lbrd[plfs])>=0)
          {
            if((ptyp>0 && ptyp<5) || pfs%2 == 0) min=max=fs;
            for(dir=maxdir[ptyp];dir>=0;dir--)
              if((ts=lbrd[(lts=plfs+pdir[ptyp][dir])])>=0)
                {
                for(s=maxs[ptyp];s>=0;s--)
                  {
                    if(ts<min)min=ts;
                    if(ts>max)max=ts;
                    if((ts=lbrd[(lts=lts+pdir[ptyp][dir])])<0 || s==0)
                    break;
                   }
                 }
            if(ptyp!=0 && ptyp<5)
              {
                if(ptyp<3)
                {
                  *(pop+pfs)=(offset-min);
                  offset=offset+max-min+1;
                }
                else
                {
                  *(pop+pfs)=(offset-pfs);
                  if(ptyp==3)offset=offset+13;
                  else offset=offset+11;
                }
              }
            else
              {
                if(pfs%2!=0)
                {
                  *(pop+pfs)=(offset-min);
                  *(pop+pfs-1)=(offset-min);
                  offset=offset+max-min+2;
                }
              }
          }
        offset=0;
    }

  for(ptyp=0;ptyp<7;ptyp++)
    for(plfs=21;plfs<99;plfs++)
    /*  if(ptyp<5 || (ptyp>4 && plfs>30 && plfs<89))  */
        if((pfs=fs=lbrd[plfs])>=0)
        {
          switch (ptyp)
            {
              case 0:
                sbns=bns+bol[pfs];
                sbnd=bnd+bol[pfs];
                break;
              case 1:
                sbns=rns+rol[pfs];
                sbnd=rnd+rol[pfs];
                break;
              case 2:
                sbns=qns+qol[pfs];
                sbnd=qnd+qol[pfs];
                break;
              case 3:
                sbns=nns+nol[pfs];
                break;
              case 4:
                sbns=kns+kol[pfs];
                break;
              case 5:
                sbns=wpns+pol[pfs];
                break;
              case 6:
                sbns=bpns+pol[pfs];
            }
          for(dir=maxdir[ptyp];dir>=0;dir--)
            if((ts=lbrd[(lts=plfs+pdir[ptyp][dir])])>=0)
              {
                for(ndir=dir-1;ndir>=0;ndir--)
                if((nds=lbrd[(lds=plfs+pdir[ptyp][ndir])])>=0)break;
                ppdir=0;
                for(s=maxs[ptyp];s>=0;s--)
                  {
                    if(ptyp<5) *(sbns+fs)=ts;
                    if(ptyp==5)
                      {
                        if(dir==2 && ndir==1)
                        {
                          *(sbns+fs)=ts;
                          *(sbns+ts)=nds;
                          ppdir=2;
                        }
                        if((dir==2 && ndir==0) || (dir==1))/* && ppdir!=2))*/
                        {
                          *(sbns+fs)=ts;
                          *(sbns+ts)=65;if(pfs> 7 && pfs<16) *(sbns+ts)=66;
                                        if(pfs>31 && pfs<40) *(sbns+ts)=67;
                                        if(pfs>47 && pfs<56) *(sbns+ts)=68;
                          ppdir=0;
                        }
                        if(dir==1 && ppdir==2)
                        {
                          *(sbns+ts)=65;if(pfs> 7 && pfs<16) *(sbns+ts)=66;
                                        if(pfs>31 && pfs<40) *(sbns+ts)=67;
                                        if(pfs>47 && pfs<56) *(sbns+ts)=68;
                        }
                      }
                    if(ptyp==6)
                      {
                        if(dir==2 && ndir==1)
                        {
                          *(sbns+fs)=ts;
                          *(sbns+ts)=nds;
                          ppdir=2;
                        }
                        if((dir==2 && ndir==0) || (dir==1))/* && ppdir!=2))*/
                        {
                          *(sbns+fs)=ts;
                          *(sbns+ts)=65;if(pfs<56 && pfs>47) *(sbns+ts)=66;
                                        if(pfs<32 && pfs>23) *(sbns+ts)=67;
                                        if(pfs<16 && pfs> 7) *(sbns+ts)=68;
                           ppdir=0;
                        }
                        if(dir==1 && ppdir==2)
                        {
                          *(sbns+ts)=65;if(pfs<56 && pfs>47) *(sbns+ts)=66;
                                        if(pfs<32 && pfs>23) *(sbns+ts)=67;
                                        if(pfs<16 && pfs> 7) *(sbns+ts)=68;
                         }
                      }
                    if(ndir>=0 && ptyp<3) *(sbnd+ts)=nds;
                    else if(ptyp<3) *(sbnd+ts)=64;
                    fs=ts;
                    if((ts=lbrd[(lts=lts+pdir[ptyp][dir])])<0 || s==0)
                      {
                        if(ndir>=0 && ptyp<5)
                        {
                          *(sbns+fs)=nds;
                          if(ptyp<3) *(sbnd+fs)=nds;
                        }
                        else
                        if(ptyp<5)
                          {
                            *(sbns+fs)=64;
                            if(ptyp<3) *(sbnd+fs)=64;
                          }
                         break;
                      }
              }
        }
} }
    
void initdata(void)
{
  memcpy(brd,ibrd,64*sizeof(char));
  memcpy(piece,ipiece,820);
  ply=0;
  rply=2;
  first[0]=0;
  hist[0].sco=0;
  hist[1].sco=0;
  fifty[0]=0;
  fifty[1]=0; 
}

void drawgraf(void)
{
}

void convert(int fs,int ts)
{
  sprintf(cmd,"%c%d%c%d",(fs&7)+'a',(fs>>3)+1,(ts&7)+'a',(ts>>3)+1);
  
}  
   
void board()
{
  int ps,fs,i;
  char pieces[]="BRQNKPbrqnkp.";

  for(ps=63;ps>=0;ps--)
  {
    fs=7-(ps&7)+(ps>>3)*8;
    i=brd[fs];
    if(i<17)i=piece[i].pt;
    else if(i==17)i=12;
         else i=piece[i].pt+6;
    printf(" %c ",pieces[i]);
    if((ps&7)==0)printf("\n");
  }
     printf("\n");
}   
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: My castling code

Post by mvanthoor »

Hi Michael :)

Even though I can understand your disappointment with regard to not getting any comments, I have to say that I didn't comment because of the code you posted. I'd love to help with anything posted in the programming forum, but to be able to do so, I have to be able to understand the problem, and, if posted, the code.

In your case, I can't understand your code without spending a large amount of time, and having to guess at what it does. You know what it does, because you've written it. I don't know what it does, but I also can't determine this at a glance. The one-letter variables such as "t" have no meaning to me. I do not understand why you need "ply" in determining if you can castle. In the post where you put your engine code, the second one starts with "int bmg". I'm guessing; "black move generation" ?

Your coding style is the complete opposite of mine, as I said in an earlier post. For some reason, I often see C programmers, and ESPECIALLY chess programmers writing in C, using shorthands as if they're still trying to write their code on punch cards. (I absolutely hate the code of many chess engines I've looked at, including parts of Stockfish.)

For example, I have a function such as this:

Code: Select all

pub fn algebraic_square_to_number(algebraic_square: &str) -> Result<Square, ()>
This is a function that takes an algebraic square such as "A1", and then converts it to a square number, in this case 0. A2 would thus be 8, and so on. It returns a result, which is either a Square (which basically is an alias for an unsigned 8 bit integer), or if it failed, it returns no result (and thus, in Rust, the return is an Error, as I said I wanted a Square as a Result).

By reading this header alone, I can see three things without actually knowing the function itself:
- It converts an algebraic square notation to a number.
- It takes the algebraic square as a string.
- It returns a result; either the square, or an error.

I could also have done this:

Code: Select all

pub fn astn(as: &str) -> i8
It is much shorter, and it would have also worked. This function would return 0-63 if the conversion worked, and -1 in case of an error. But, if I show this function header to someone, he knows nothing. The questions are:
- What does "astn()" do?
- What is in the "as" string?
- What is in the i8?
- Does it mean anything if the result is negative or positive; is negative an error, or part of the value range?

Please note that I'm not trying to bash you here, nor convince you to change your coding style. I'm only telling you why I didn't take a stab at trying to help. Not because I don't want to, not because of you personally, but merely because of the code being so opaque that I feel it would take me too much time to decipher what it is actually doing (and why).

You've noted this problem with your memory. To be honest, *I* have that problem with your code as well. I have to remember what each line is doing, and how many levels of if-statements deep I am. It's hard to remember and keep track. Maybe, as you're writing a new engine from scratch, it would be a good moment to try and change your style from mnemonic-style to more descriptive. It might assist with your memory problem, because you don't have to remember everything; you can just read what it is doing. If at all possible, keep the nesting down if you can. Instead of nesting all the things, put the result of the IF's in descriptive variables, and then if you have to do something if everything is true, you can just make an if-chain with those variables without nesting.

For Rust, someone actually wrote a macro that specifically facilitates this, even without having to put the intermediate stuff in variables. It's even called if_chain... (because in many languages "if_chain" has become a default pattern).

Code: Select all

    if_chain! {
        if length == 1;
        if let Some(x) = part.chars().next();
        if x == DASH;
        then {
            char_ok += 1
        }
    }
You don't know what this code does or where it comes from (it's part of the FEN-parser in my engine), but you can immediately see:

- If the length of what I'm checking is 1
- And the thing I'm checking has a character (which I'll call x)
- And x is a DASH (-)
- Then that character is OK, and I increment the counter that keeps track of OK characters by one.

This is also from the FEN-parser; and yes, except for the header, this is the entire function. I'm sure you can immediately see what part of the FEN it parses...

Code: Select all

    let mut result = ERROR;
    
    if_chain! {
        if part.len() == 1;
        if let Some(x) = part.chars().next();
        if WHITE_OR_BLACK.contains(x);
        then {
	    result = OK;
            match x {
                'w' => board.game_state.active_color = WHITE as u8,
                'b' => board.game_state.active_color = BLACK as u8,
                _ => (),
            }
        }
    }
    
    return result;
The equivalent in C would be something like this (pseudo-code... I haven't written C in YEARS... sorry).

Code: Select all

bool lenght_ok = len(part) == 1;
char x = get_next_char(part);
bool x_ok = char_in_string(x, WHITE_OR_BLACK);
bool result = ERROR;

if (
	length_ok
	&& x != null
	&& x_ok
) {
        result = OK;
	switch (x) {
			'w': { board.game_state.active_color = WHITE; break; }
			'b': { board.game_state.active_color = BLACK; break; }
	}
}

return result;
Even if this more descriptive coding style doesn't help with your memory problem, I'm convinced you would receive more, faster, and better help whenever you ask for assistance with regard to the code you've written. At least, you would from me, gladly.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: My castling code

Post by Michael Sherwin »

mvanthoor wrote: Sun Apr 19, 2020 2:41 pm Hi Michael :)

Even though I can understand your disappointment with regard to not getting any comments, I have to say that I didn't comment because of the code you posted. I'd love to help with anything posted in the programming forum, but to be able to do so, I have to be able to understand the problem, and, if posted, the code.

In your case, I can't understand your code without spending a large amount of time, and having to guess at what it does. You know what it does, because you've written it. I don't know what it does, but I also can't determine this at a glance. The one-letter variables such as "t" have no meaning to me. I do not understand why you need "ply" in determining if you can castle. In the post where you put your engine code, the second one starts with "int bmg". I'm guessing; "black move generation" ?

Your coding style is the complete opposite of mine, as I said in an earlier post. For some reason, I often see C programmers, and ESPECIALLY chess programmers writing in C, using shorthands as if they're still trying to write their code on punch cards. (I absolutely hate the code of many chess engines I've looked at, including parts of Stockfish.)

For example, I have a function such as this:

Code: Select all

pub fn algebraic_square_to_number(algebraic_square: &str) -> Result<Square, ()>
This is a function that takes an algebraic square such as "A1", and then converts it to a square number, in this case 0. A2 would thus be 8, and so on. It returns a result, which is either a Square (which basically is an alias for an unsigned 8 bit integer), or if it failed, it returns no result (and thus, in Rust, the return is an Error, as I said I wanted a Square as a Result).

By reading this header alone, I can see three things without actually knowing the function itself:
- It converts an algebraic square notation to a number.
- It takes the algebraic square as a string.
- It returns a result; either the square, or an error.

I could also have done this:

Code: Select all

pub fn astn(as: &str) -> i8
It is much shorter, and it would have also worked. This function would return 0-63 if the conversion worked, and -1 in case of an error. But, if I show this function header to someone, he knows nothing. The questions are:
- What does "astn()" do?
- What is in the "as" string?
- What is in the i8?
- Does it mean anything if the result is negative or positive; is negative an error, or part of the value range?

Please note that I'm not trying to bash you here, nor convince you to change your coding style. I'm only telling you why I didn't take a stab at trying to help. Not because I don't want to, not because of you personally, but merely because of the code being so opaque that I feel it would take me too much time to decipher what it is actually doing (and why).

You've noted this problem with your memory. To be honest, *I* have that problem with your code as well. I have to remember what each line is doing, and how many levels of if-statements deep I am. It's hard to remember and keep track. Maybe, as you're writing a new engine from scratch, it would be a good moment to try and change your style from mnemonic-style to more descriptive. It might assist with your memory problem, because you don't have to remember everything; you can just read what it is doing. If at all possible, keep the nesting down if you can. Instead of nesting all the things, put the result of the IF's in descriptive variables, and then if you have to do something if everything is true, you can just make an if-chain with those variables without nesting.

For Rust, someone actually wrote a macro that specifically facilitates this, even without having to put the intermediate stuff in variables. It's even called if_chain... (because in many languages "if_chain" has become a default pattern).

Code: Select all

    if_chain! {
        if length == 1;
        if let Some(x) = part.chars().next();
        if x == DASH;
        then {
            char_ok += 1
        }
    }
You don't know what this code does or where it comes from (it's part of the FEN-parser in my engine), but you can immediately see:

- If the length of what I'm checking is 1
- And the thing I'm checking has a character (which I'll call x)
- And x is a DASH (-)
- Then that character is OK, and I increment the counter that keeps track of OK characters by one.

This is also from the FEN-parser; and yes, except for the header, this is the entire function. I'm sure you can immediately see what part of the FEN it parses...

Code: Select all

    let mut result = ERROR;
    
    if_chain! {
        if part.len() == 1;
        if let Some(x) = part.chars().next();
        if WHITE_OR_BLACK.contains(x);
        then {
	    result = OK;
            match x {
                'w' => board.game_state.active_color = WHITE as u8,
                'b' => board.game_state.active_color = BLACK as u8,
                _ => (),
            }
        }
    }
    
    return result;
The equivalent in C would be something like this (pseudo-code... I haven't written C in YEARS... sorry).

Code: Select all

bool lenght_ok = len(part) == 1;
char x = get_next_char(part);
bool x_ok = char_in_string(x, WHITE_OR_BLACK);
bool result = ERROR;

if (
	length_ok
	&& x != null
	&& x_ok
) {
        result = OK;
	switch (x) {
			'w': { board.game_state.active_color = WHITE; break; }
			'b': { board.game_state.active_color = BLACK; break; }
	}
}

return result;
Even if this more descriptive coding style doesn't help with your memory problem, I'm convinced you would receive more, faster, and better help whenever you ask for assistance with regard to the code you've written. At least, you would from me, gladly.
Thanks for your reply, you put a lot of work into it! Longer more descriptive variable names are not more descriptive to me. Let me give an insufficient example meaning it is not really this bad. When I read in my code "WP" I see WHITE_PAWN. When I read WHITE_PAWN I see WHITE and I see PAWN. PAWN? What kind of PAWN, oh white. WHITE? White what, oh pawn. Like I said I'm not that bad but length to read is time and time is my enemy. WP is more descriptive to me because I have trained my memory to recognize it. Therefore in general w = white, p = pawn, pc = piece and t = thread, etc. Believe me it is a catch 22.
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: My castling code

Post by mar »

mvanthoor wrote: Sun Apr 19, 2020 2:41 pm For some reason, I often see C programmers, and ESPECIALLY chess programmers writing in C, using shorthands as if they're still trying to write their code on punch cards. (I absolutely hate the code of many chess engines I've looked at, including parts of Stockfish.)
Funny that this spit is coming from someone who has written exactly 0 chess engines. Where's your masterpiece to be found? perhaps_you_believe_that_variable_names_like_this_will_make_your_code_better?
Martin Sedlak