[comp.sources.games] v04i037: gnuchess2 - latest version of the GNU Chess program, Part01/04

games@tekred.TEK.COM (06/11/88)

Submitted by: John Stanback <jhs@hpltbm.HP.COM>
Comp.sources.games: Volume 4, Issue 37
Archive-name: gnuchess2/Part01

	[NOTE: The gnuchess.c file is split into two parts for network
	 distribution. The Makefile, as modified, puts them back together
	 into one .c file.  -br]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 4)."
# Contents:  README MANIFEST COPYING gnuchess.c1
# Wrapped by billr@saab on Fri Jun 10 17:01:29 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(685 characters\)
sed "s/^X//" >README <<'END_OF_README'
XThis is the latest version of GNU Chess.
X
XI've made quite a few modifications since the last version
Xwas posted (in December or January).  I've split the program
Xinto two parts -- a chess engine and an interface section.  This
Xmay make it easier for people to customize an interface for
Xtheir own needs.  I've included two interfaces, one is a
Xsimple alpha board display and another is for use in conjunction
Xwith Sun Chesstool or Xchess.  I may send alpha and graphics
Xinterfaces for MSDOS at a later date.  As far as chess ability
Xgoes this version is about 25% faster and has several new
Xheuristics so it should play substantially better.
X
XJohn Stanback
Xjhs@hpltbm.HP.COM
XJune 1988
END_OF_README
if test 685 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MANIFEST -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MANIFEST\"
else
echo shar: Extracting \"MANIFEST\" \(444 characters\)
sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X COPYING                   1	
X MANIFEST                  1	This shipping list
X Makefile                  2	
X README                    1	
X gnuchess.book             2	
X gnuchess.c1               1	
X gnuchess.c2               4	
X gnuchess.h                2	
X gnuchess.man              2	
X nondsp.c                  3	
X uxdsp.c                   3	
END_OF_MANIFEST
if test 444 -ne `wc -c <MANIFEST`; then
    echo shar: \"MANIFEST\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f COPYING -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"COPYING\"
else
echo shar: Extracting \"COPYING\" \(6441 characters\)
sed "s/^X//" >COPYING <<'END_OF_COPYING'
X
X		 GNU CHESS GENERAL PUBLIC LICENSE
X
X Copyright (C) 1986,1987 Free Software Foundation, Inc.
X
X Everyone is permitted to copy and distribute verbatim copies
X of this license, but changing it is not allowed.
X
X  The license agreements of most software companies keep you at the
Xmercy of those companies.  By contrast, our general public license is
Xintended to give everyone the right to share GNU Chess.  To make
Xsure that you get the rights we want you to have, we need to make
Xrestrictions that forbid anyone to deny you these rights or to ask you
Xto surrender the rights.  Hence this license agreement.
X
X  Specifically, we want to make sure that you have the right to give
Xaway copies of GNU Chess, that you receive source code or else can get it
Xif you want it, that you can change GNU Chess or use pieces of it in new
Xfree programs, and that you know you can do these things.
X
X  To make sure that everyone has such rights, we have to forbid you to
Xdeprive anyone else of these rights.  For example, if you distribute
Xcopies of GNU Chess, you must give the recipients all the rights that you
Xhave.  You must make sure that they, too, receive or can get the
Xsource code.  And you must tell them their rights.
X
X  Also, for our own protection, we must make certain that everyone
Xfinds out that there is no warranty for GNU Chess.  If GNU Chess is
Xmodified by someone else and passed on, we want its recipients to know
Xthat what they have is not what we distributed, so that any problems
Xintroduced by others will not reflect on our reputation.
X
X  Therefore the Free Software Foundation, Inc. makes the following
Xterms which say what you must do to be allowed to distribute or change
XGNU Chess.
X
X			COPYING POLICIES
X
X  1. You may copy and distribute verbatim copies of GNU Chess source
Xcode as you receive it, in any medium, provided that you conspicuously
Xand appropriately publish on each file a valid copyright notice
X"Copyright (C) 1986,1987 Free Software Foundation, Inc.", containing the
Xyear of last change for the file in question; keep intact the notices
Xon all files that refer to this License Agreement and to the absence
Xof any warranty; and give any other recipients of the GNU Chess
Xprogram a copy of this License Agreement along with the program.
X
X  2. You may modify your copy or copies of GNU Chess source code or
Xany portion of it, and copy and distribute such modifications under
Xthe terms of Paragraph 1 above, provided that you also do the following:
X
X    a) cause the modified files to carry prominent notices stating
X    who last changed such files and the date of any change; and
X
X    b) cause the whole of any work that you distribute or publish,
X    that in whole or in part contains or is a derivative of GNU Chess
X    or any part thereof, to be freely distributed
X    and licensed to all third parties on terms identical to those
X    contained in this License Agreement (except that you may choose
X    to grant more extensive warranty protection to third parties,
X    at your option).
X
X    c) if the modified program serves as a text editor, cause it
X    when started running in the simplest and usual way, to print
X    an announcement including a valid copyright notice ("Copyright
X    (C)", the year of authorship, and all copyright owners' names),
X    saying that there is no warranty (or else, saying that you provide
X    a warranty) and that users may redistribute the program under
X    these conditions, and telling the user how to view a copy of
X    this License Agreement.
X
X  3. You may copy and distribute GNU Chess or any portion of it in
Xcompiled, executable or object code form under the terms of Paragraphs
X1 and 2 above provided that you do the following:
X
X    a) cause each such copy of GNU Chess to be accompanied by the
X    corresponding machine-readable source code; or
X
X    b) cause each such copy of GNU Chess to be accompanied by a
X    written offer, with no time limit, to give any third party
X    free (except for a nominal shipping charge) machine readable
X    copy of the corresponding source code; or
X
X    c) in the case of a recipient of GNU Chess in compiled, executable
X    or object code form (without the corresponding source code) you
X    shall cause copies you distribute to be accompanied by a copy
X    of the written offer of source code which you received along
X    with the copy of GNU Chess.
X
X  4. You may not copy, sublicense, distribute or transfer GNU Chess
Xexcept as expressly provided under this License Agreement.  Any attempt
Xotherwise to copy, sublicense, distribute or transfer GNU Chess is void and
Xyour rights to use GNU Chess under this License agreement shall be
Xautomatically terminated.  However, parties who have received computer
Xsoftware programs from you with this License Agreement will not have
Xtheir licenses terminated so long as such parties remain in full compliance.
X
XYour comments and suggestions about our licensing policies and our
Xsoftware are welcome!  Please contact the Free Software Foundation, Inc.,
X1000 Mass Ave, Cambridge, MA 02138, or call (617) 876-3296.
X
X			   NO WARRANTY
X
X  BECAUSE GNU CHESS IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
XNO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
XWHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
XAND/OR OTHER PARTIES PROVIDE GNU CHESS "AS IS" WITHOUT WARRANTY OF ANY
XKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
XIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
XPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
XPROGRAM IS WITH YOU.  SHOULD THE GNU CHESS PROGRAM PROVE DEFECTIVE,
XYOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
X
X IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL FREE SOFTWARE
XFOUNDATION, INC., AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
XREDISTRIBUTE GNU CHESS AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
XDAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
XINCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
XINABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
XBEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
XFAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
XFREE SOFTWARE FOUNDATION, INC.) THE PROGRAM, EVEN IF YOU HAVE BEEN
XADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY
XOTHER PARTY.
X======================================================================
X
END_OF_COPYING
if test 6441 -ne `wc -c <COPYING`; then
    echo shar: \"COPYING\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f gnuchess.c1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"gnuchess.c1\"
else
echo shar: Extracting \"gnuchess.c1\" \(44471 characters\)
sed "s/^X//" >gnuchess.c1 <<'END_OF_gnuchess.c1'
X/*
X  C source for CHESS.
X
X  Revision: 5-23-88
X
X  Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
X  Copyright (c) 1988  John Stanback
X
X  This file is part of CHESS.
X
X  CHESS is distributed in the hope that it will be useful,
X  but WITHOUT ANY WARRANTY.  No author or distributor
X  accepts responsibility to anyone for the consequences of using it
X  or for whether it serves any particular purpose or works at all,
X  unless he says so in writing.  Refer to the CHESS General Public
X  License for full details.
X
X  Everyone is granted permission to copy, modify and redistribute
X  CHESS, but only under the conditions described in the
X  CHESS General Public License.   A copy of this license is
X  supposed to have been given to you along with CHESS so you
X  can know your rights and responsibilities.  It should be in a
X  file named COPYING.  Among other things, the copyright notice
X  and this notice must be preserved on all copies.
X*/
X
X
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef MSDOS
X#include <stdlib.h>
X#include <time.h>
X#include <alloc.h>
X#define ttblsz 4096
X#else
X#include <sys/param.h>
X#include <sys/times.h>
X#define ttblsz 16384
X#define huge
X#endif MSDOS
X
X
X#define neutral 2
X#define white 0
X#define black 1 
X#define no_piece 0
X#define pawn 1
X#define knight 2
X#define bishop 3
X#define rook 4
X#define queen 5
X#define king 6
X#define valueP 100
X#define valueN 350
X#define valueB 355
X#define valueR 550
X#define valueQ 1100
X#define valueK 1200
X#define ctlP 0x4000
X#define ctlN 0x2800
X#define ctlB 0x1800
X#define ctlR 0x0400
X#define ctlQ 0x0200
X#define ctlK 0x0100
X#define ctlBQ 0x1200
X#define ctlRQ 0x0600
X#define ctlNN 0x2000
X#define pxx " PNBRQK"
X#define qxx " pnbrqk"
X#define rxx "12345678"
X#define cxx "abcdefgh"
X#define check 0x0001
X#define capture 0x0002
X#define draw 0x0004
X#define promote 0x0008
X#define cstlmask 0x0010
X#define epmask 0x0020
X#define exact 0x0040
X#define pwnthrt 0x0080
X#define truescore 0x0001
X#define lowerbound 0x0002
X#define upperbound 0x0004
X#define maxdepth 30
X#define true 1
X#define false 0
X#define absv(x) ((x) < 0 ? -(x) : (x))
X#define taxicab(a,b) (abs(column[a]-column[b]) + abs(row[a]-row[b]))
X
Xstruct leaf
X  {
X    short f,t,score,reply;
X    unsigned short flags;
X  };
Xstruct GameRec
X  {
X    unsigned short gmove;
X    short score,depth,time,piece,color;
X    long nodes;
X  };
Xstruct TimeControlRec
X  {
X    short moves[2];
X    long clock[2];
X  };
Xstruct BookEntry
X  {
X    struct BookEntry *next;
X    unsigned short *mv;
X  };
Xstruct hashval
X  {
X    unsigned long bd;
X    unsigned short key;
X  };
Xstruct hashentry
X  {
X    unsigned long hashbd;
X    unsigned short mv,flags;
X    short score,depth;
X  };
X
Xchar mvstr1[5],mvstr2[5],mvstr3[6];
Xstruct leaf Tree[1500],*root;
Xshort TrPnt[maxdepth],board[64],color[64];
Xshort row[64],column[64],locn[8][8],Pindex[64],svalue[64];
Xshort PieceList[2][16],PieceCnt[2],atak[2][64],PawnCnt[2][8];
Xshort castld[2],kingmoved[2],mtl[2],pmtl[2],emtl[2],hung[2];
Xshort c1,c2,*atk1,*atk2,*PC1,*PC2,EnemyKing;
Xshort mate,post,opponent,computer,Sdepth,Awindow,Bwindow,dither;
Xlong ResponseTime,ExtraTime,Level,et,et0,time0,cputimer,ft;
Xlong NodeCnt,evrate,ETnodes,EvalNodes,HashCnt;
Xshort quit,reverse,bothsides,hashflag,InChk,player,force,easy,beep;
Xshort wking,bking,FROMsquare,TOsquare,timeout,Zscore,zwndw,xwndw,slk;
Xshort INCscore;
Xshort HasPawn[2],HasKnight[2],HasBishop[2],HasRook[2],HasQueen[2];
Xshort ChkFlag[maxdepth],CptrFlag[maxdepth],PawnThreat[maxdepth];
Xshort Pscore[maxdepth],Tscore[maxdepth],Threat[maxdepth];
Xstruct GameRec GameList[240];
Xshort GameCnt,Game50,epsquare,lpost,rcptr,contempt;
Xshort MaxSearchDepth,Xscore;
Xstruct BookEntry *Book;
Xstruct TimeControlRec TimeControl;
Xshort TCflag,TCmoves,TCminutes,OperatorTime;
Xshort otherside[3]={1,0,2};
Xshort rank7[3]={6,1,0};
Xshort map[64]=
X   {0,1,2,3,4,5,6,7,
X    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
X    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
X    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
X    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
X    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
X    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
X    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77};
Xshort unmap[120]=
X   {0,1,2,3,4,5,6,7,-1,-1,-1,-1,-1,-1,-1,-1,
X    8,9,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,
X    16,17,18,19,20,21,22,23,-1,-1,-1,-1,-1,-1,-1,-1,
X    24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
X    32,33,34,35,36,37,38,39,-1,-1,-1,-1,-1,-1,-1,-1,
X    40,41,42,43,44,45,46,47,-1,-1,-1,-1,-1,-1,-1,-1,
X    48,49,50,51,52,53,54,55,-1,-1,-1,-1,-1,-1,-1,-1,
X    56,57,58,59,60,61,62,63};
Xshort Dcode[120]= 
X   {0,1,1,1,1,1,1,1,0,0,0,0,0,0,0x0E,0x0F,
X    0x10,0x11,0x12,0,0,0,0,0,0,0,0,0,0,0,0x0F,0x1F,
X    0x10,0x21,0x11,0,0,0,0,0,0,0,0,0,0,0x0F,0,0,
X    0x10,0,0,0x11,0,0,0,0,0,0,0,0,0x0F,0,0,0,
X    0x10,0,0,0,0x11,0,0,0,0,0,0,0x0F,0,0,0,0,
X    0x10,0,0,0,0,0x11,0,0,0,0,0x0F,0,0,0,0,0,
X    0x10,0,0,0,0,0,0x11,0,0,0x0F,0,0,0,0,0,0,
X    0x10,0,0,0,0,0,0,0x11};
Xshort Stboard[64]=
X   {rook,knight,bishop,queen,king,bishop,knight,rook,
X    pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
X    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,
X    pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
X    rook,knight,bishop,queen,king,bishop,knight,rook};
Xshort Stcolor[64]=
X   {white,white,white,white,white,white,white,white,
X    white,white,white,white,white,white,white,white,
X    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
X    black,black,black,black,black,black,black,black,
X    black,black,black,black,black,black,black,black};
Xshort sweep[7]= {false,false,false,true,true,true,false};
Xshort Dpwn[3]={4,6,0};
Xshort Dstart[7]={6,4,8,4,0,0,0};
Xshort Dstop[7]={7,5,15,7,3,7,7};
Xshort Dir[16]={1,0x10,-1,-0x10,0x0F,0x11,-0x0F,-0x11,
X               0x0E,-0x0E,0x12,-0x12,0x1F,-0x1F,0x21,-0x21};
Xshort Pdir[34]={0,0x38,0,0,0,0,0,0,0,0,0,0,0,0,0x02,0x35,
X                0x38,0x35,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0x02,
X                0,0x02};
Xshort pbit[7]={0,0x01,0x02,0x04,0x08,0x10,0x20};
Xunsigned short killr0[maxdepth],killr1[maxdepth],killr2[maxdepth];
Xunsigned short killr3[maxdepth],PrVar[maxdepth];
Xunsigned short PV,hint,Swag0,Swag1,Swag2,Swag3,Swag4;
Xunsigned short hashkey;
Xunsigned long hashbd;
Xstruct hashval hashcode[2][7][64];
Xstruct hashentry huge *ttable,*ptbl;
Xunsigned char history[8192];
X
Xshort Mwpawn[64],Mbpawn[64],Mknight[2][64],Mbishop[2][64];
Xshort Mking[2][64],Kfield[2][64];
Xshort value[7]={0,valueP,valueN,valueB,valueR,valueQ,valueK};
Xshort control[7]={0,ctlP,ctlN,ctlB,ctlR,ctlQ,ctlK};
Xshort PassedPawn0[8]={0,60,80,120,200,360,600,800};
Xshort PassedPawn1[8]={0,30,40,60,100,180,300,800};
Xshort PassedPawn2[8]={0,15,25,35,50,90,140,800};
Xshort PassedPawn3[8]={0,5,10,15,20,30,140,800};
Xshort ISOLANI[8] = {-12,-16,-20,-24,-24,-20,-16,-12};
Xshort BACKWARD[8] = {-6,-10,-15,-21,-28,-28,-28,-28};
Xshort BMBLTY[14] = {-2,0,2,4,6,8,10,12,13,14,15,16,16,16};
Xshort RMBLTY[14] = {0,2,4,6,8,10,11,12,13,14,14,14,14,14};
Xshort Kthreat[16] = {0,-8,-20,-36,-52,-68,-80,-80,-80,-80,-80,-80,
X                     -80,-80,-80,-80};
Xshort KNIGHTPOST,KNIGHTSTRONG,BISHOPSTRONG,KATAK,KBNKsq;
Xshort PEDRNK2B,PWEAKH,PADVNCM,PADVNCI,PAWNSHIELD,PDOUBLED,PBLOK;
Xshort RHOPN,RHOPNX,KHOPN,KHOPNX,KSFTY;
Xshort ATAKD,HUNGP,HUNGX,KCASTLD,KMOVD,XRAY,PINVAL;
Xshort stage,stage2,Zwmtl,Zbmtl,Developed[2],PawnStorm;
Xshort PawnBonus,BishopBonus,RookBonus;
Xshort KingOpening[64]=
X   {  0,  0, -4,-10,-10, -4,  0,  0,
X     -4, -4, -8,-12,-12, -8, -4, -4,
X    -12,-16,-20,-20,-20,-20,-16,-12,
X    -16,-20,-24,-24,-24,-24,-20,-16,
X    -16,-20,-24,-24,-24,-24,-20,-16,
X    -12,-16,-20,-20,-20,-20,-16,-12,
X     -4, -4, -8,-12,-12, -8, -4, -4,
X      0,  0, -4,-10,-10, -4,  0,  0};
Xshort KingEnding[64]=
X   { 0, 4, 8,12,12, 8, 4, 0,
X     4,16,20,24,24,20,16, 4,
X     8,20,28,32,32,28,20, 8,
X    12,24,32,36,36,32,24,12,
X    12,24,32,36,36,32,24,12,
X     8,20,28,32,32,28,20, 8,
X     4,16,20,24,24,20,16, 4,
X     0, 4, 8,12,12, 8, 4, 0};
Xshort KBNK[64]=
X   {99,90,80,70,60,50,40,40,
X    90,80,60,50,40,30,20,40,
X    80,60,40,30,20,10,30,50,
X    70,50,30,10, 0,20,40,60,
X    60,40,20, 0,10,30,50,70,
X    50,30,10,20,30,40,60,80,
X    40,20,30,40,50,60,80,90,
X    40,40,50,60,70,80,90,99};
Xshort pknight[64]=
X   { 0, 4, 8,10,10, 8, 4, 0,
X     4, 8,16,20,20,16, 8, 4,
X     8,16,24,28,28,24,16, 8,
X    10,20,28,32,32,28,20,10,
X    10,20,28,32,32,28,20,10,
X     8,16,24,28,28,24,16, 8,
X     4, 8,16,20,20,16, 8, 4,
X     0, 4, 8,10,10, 8, 4, 0};
Xshort pbishop[64]=
X   {14,14,14,14,14,14,14,14,
X    14,22,18,18,18,18,22,14,
X    14,18,22,22,22,22,18,14,
X    14,18,22,22,22,22,18,14,
X    14,18,22,22,22,22,18,14,
X    14,18,22,22,22,22,18,14,
X    14,22,18,18,18,18,22,14,
X    14,14,14,14,14,14,14,14};
Xshort PawnAdvance[64]=
X   { 0, 0, 0, 0, 0, 0, 0, 0,
X     4, 4, 4, 0, 0, 4, 4, 4,
X     6, 8, 2,10,10, 2, 8, 6,
X     6, 8,12,16,16,12, 8, 6,
X     8,12,16,24,24,16,12, 8,
X    12,16,24,32,32,24,16,12,
X    12,16,24,32,32,24,16,12,
X     0, 0, 0, 0, 0, 0, 0, 0};
X     
X     
X
Xmain(argc,argv)
Xint argc; char *argv[];
X{
X#ifdef MSDOS
X  ttable = (struct hashentry huge *)farmalloc(ttblsz *
X           (unsigned long)sizeof(struct hashentry));
X#else
X  ttable = (struct hashentry *)malloc(ttblsz *
X           (unsigned long)sizeof(struct hashentry));
X#endif
X  Level = 0; TCflag = false; OperatorTime = 0;
X  if (argc == 2) Level = atoi(argv[1]);
X  if (argc == 3)
X    {
X      TCmoves = atoi(argv[1]); TCminutes = atoi(argv[2]); TCflag = true;
X    }
X  Initialize();
X  NewGame();
X  while (!(quit))
X    {
X      if (bothsides && !mate) SelectMove(opponent,1); else InputCommand();
X      if (!(quit || mate || force)) SelectMove(computer,1);
X    }
X  ExitChess();
X}
X
X
X
X/* ............    INTERFACE ROUTINES    ........................... */
X
Xint VerifyMove(s,iop,mv)
Xchar s[];
Xshort iop;
Xunsigned short *mv;
X
X/*
X   Compare the string 's' to the list of legal moves available for the 
X   opponent. If a match is found, make the move on the board. 
X*/
X
X{
Xstatic short pnt,tempb,tempc,tempsf,tempst,cnt;
Xstatic struct leaf xnode;
Xstruct leaf *node;
X
X  *mv = 0;
X  if (iop == 2)
X    {
X      UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
X      return(false);
X    }
X  cnt = 0;
X  MoveList(opponent,2);
X  pnt = TrPnt[2];
X  while (pnt < TrPnt[3])
X    {
X      node = &Tree[pnt++];
X      algbr(node->f,node->t,node->flags & cstlmask);
X      if (strcmp(s,mvstr1) == 0 || strcmp(s,mvstr2) == 0 ||
X          strcmp(s,mvstr3) == 0)
X        {
X          cnt++; xnode = *node;
X        }
X    }
X  if (cnt == 1)
X    {
X      MakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
X      if (SqAtakd(PieceList[opponent][0],computer))
X        {
X          UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
X          ShowMessage("Illegal Move!!");
X          return(false);
X        }
X      else
X        {
X          if (iop == 1) return(true);
X          if (xnode.flags & epmask) UpdateDisplay(0,0,1,0);
X          else UpdateDisplay(xnode.f,xnode.t,0,xnode.flags & cstlmask);
X          if (xnode.flags & cstlmask) Game50 = GameCnt;
X          else if (board[xnode.t] == pawn || (xnode.flags & capture)) 
X            Game50 = GameCnt;
X          GameList[GameCnt].depth = GameList[GameCnt].score = 0;
X          GameList[GameCnt].nodes = 0;
X          ElapsedTime(1);
X          GameList[GameCnt].time = (short)et;
X          TimeControl.clock[opponent] -= et;
X          --TimeControl.moves[opponent];
X          *mv = (xnode.f << 8) + xnode.t;
X          algbr(xnode.f,xnode.t,false);
X          return(true);
X        } 
X    }
X  if (cnt > 1) ShowMessage("Ambiguous Move!");
X  return(false);
X}
X
X
XNewGame()
X
X/*
X   Reset the board and other variables to start a new game.
X*/
X
X{
Xshort l,r,c,p;
X
X  mate = quit = reverse = bothsides = post = false;
X  hashflag = force = PawnStorm = false;
X  easy = beep = rcptr = true;
X  lpost =  NodeCnt = epsquare = et0 = 0;
X  dither = 0;
X  Awindow = 90;
X  Bwindow = 90;
X  xwndw = 90;
X  MaxSearchDepth = 29;
X  contempt = 0;
X  GameCnt = -1; Game50 = 0;
X  Zwmtl = Zbmtl = 0;
X  Developed[white] = Developed[black] = false;
X  castld[white] = castld[black] = false;
X  kingmoved[white] = kingmoved[black] = 0;
X  PawnThreat[0] = CptrFlag[0] = Threat[0] = false;
X  Pscore[0] = 12000; Tscore[0] = 12000;
X  opponent = white; computer = black;
X  for (r = 0; r < 8; r++)
X    for (c = 0; c < 8; c++)
X      {
X        l = 8*r+c; locn[r][c] = l;
X        row[l] = r; column[l] = c;
X        board[l] = Stboard[l]; color[l] = Stcolor[l];
X      }
X  for (c = white; c <= black; c++)
X    for (p = pawn; p <= king; p++)
X      for (l = 0; l < 64; l++)
X        {
X          hashcode[c][p][l].key = (unsigned short)rand();
X          hashcode[c][p][l].bd = ((unsigned long)rand() << 16) +
X                                 (unsigned long)rand();
X        }
X  ClrScreen();
X  if (TCflag) SetTimeControl();
X  else if (Level == 0) SelectLevel();
X  UpdateDisplay(0,0,1,0);
X  InitializeStats();
X  time0 = time((long *)0);
X  ElapsedTime(1);
X  GetOpenings();
X}
X
X
Xalgbr(f,t,flag)
Xshort f,t,flag;
X{
X  mvstr1[0] = cxx[column[f]]; mvstr1[1] = rxx[row[f]];
X  mvstr1[2] = cxx[column[t]]; mvstr1[3] = rxx[row[t]];
X  mvstr2[0] = qxx[board[f]];
X  mvstr2[1] = mvstr1[2]; mvstr2[2] = mvstr1[3];
X  mvstr1[4] = '\0'; mvstr2[3] = '\0';
X  if (flag)
X    if (t > f) strcpy(mvstr2,"o-o");
X    else strcpy(mvstr2,"o-o-o");
X
X  if (board[f] == pawn) mvstr3[0] = mvstr1[0];
X  else mvstr3[0] = qxx[board[f]];
X  if (color[t] != neutral)
X    {
X      mvstr3[1] = ':';
X      mvstr3[2] = mvstr1[2];
X      mvstr3[3] = mvstr1[3];
X      mvstr3[4] = '\0';
X    }
X  else if (board[f] == pawn)
X    {
X      mvstr3[1] = mvstr1[3];
X      mvstr3[2] = '\0';
X    }
X  else
X    {
X      mvstr3[1] = mvstr1[0];
X      mvstr3[2] = mvstr1[1];
X      mvstr3[3] = mvstr1[2];
X      mvstr3[4] = mvstr1[3];
X      mvstr3[5] = '\0';
X    }
X}
X
X
X/* ............    MOVE GENERATION & SEARCH ROUTINES    .............. */
X
XSelectMove(side,iop)
Xshort side,iop;
X
X/*
X   Select a move by calling function search() at progressively deeper 
X   ply until time is up or a mate or draw is reached. An alpha-beta 
X   window of -90 to +90 points is set around the score returned from the 
X   previous iteration. If Sdepth != 0 then the program has correctly 
X   predicted the opponents move and the search will start at a depth of 
X   Sdepth+1 rather than a depth of 1. 
X*/
X
X{
Xstatic short i,alpha,beta,score,tempb,tempc,tempsf,tempst,xside,rpt;
X
X  timeout = false;
X  xside = otherside[side];
X  if (iop != 2) player = side;
X  if (TCflag)
X    {
X      ResponseTime = (TimeControl.clock[side]) /
X                     (TimeControl.moves[side] + 3) -
X                     OperatorTime;
X      ResponseTime += (ResponseTime*TimeControl.moves[side])/(2*TCmoves+1);
X    }
X  else ResponseTime = Level;
X  if (iop == 2) ResponseTime = 999;
X  if (Sdepth > 0 && root->score > Zscore-zwndw) ResponseTime -= ft;
X  else if (ResponseTime < 1) ResponseTime = 1;
X  ExtraTime = 0;
X  ExaminePosition();
X  ScorePosition(side,&score);
X  Pscore[0] = -score;
X  ShowSidetomove();
X  
X  if (Sdepth == 0)
X  {
X    ZeroTTable();
X    SearchStartStuff(side);
X    for (i = 0; i < 8192; i++) history[i] = 0;
X    FROMsquare = TOsquare = -1;
X    PV = 0;
X    if (iop != 2) hint = 0;
X    for (i = 0; i < maxdepth; i++)
X     PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
X     
X    alpha = -9000; beta = 9000;
X    rpt = 0;
X    TrPnt[1] = 0; root = &Tree[0];
X    MoveList(side,1);
X    for (i = TrPnt[1]; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
X    if (Book != NULL) OpeningBook();
X    if (Book != NULL) timeout = true;
X    NodeCnt = ETnodes = EvalNodes = HashCnt = 0;
X    Zscore = 0; zwndw = 20;
X  }
X  
X  while (!timeout && Sdepth < MaxSearchDepth)
X    {
X      Sdepth++;
X      ShowDepth(' ');
X      score = search(side,1,Sdepth,alpha,beta,PrVar,&rpt);
X      for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
X      if (score < alpha && !timeout)
X        {
X          ShowDepth('-');
X          ExtraTime = 10*ResponseTime;
X          ZeroTTable();
X          score = search(side,1,Sdepth,-9000,beta,PrVar,&rpt);
X        }
X      if (score > beta && !timeout && !(root->flags & exact))
X        {
X          ShowDepth('+');
X          ExtraTime = 0;
X          ZeroTTable();
X          score = search(side,1,Sdepth,alpha,9000,PrVar,&rpt);
X        }
X      score = root->score;
X      if (!timeout)
X        for (i = TrPnt[1]+1; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
X      ShowResults(score,PrVar,'.');
X      for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
X      if (score > Zscore-zwndw && score > Tree[1].score+250) ExtraTime = 0;
X      else if (score > Zscore-3*zwndw) ExtraTime = ResponseTime;
X      else ExtraTime = 3*ResponseTime;
X      if (root->flags & exact) timeout = true;
X      if (Tree[1].score < -9000) timeout = true;
X      if (4*et > 2*ResponseTime + ExtraTime) timeout = true;
X      if (!timeout)
X        {
X          Tscore[0] = score;
X          if (Zscore == 0) Zscore = score;
X          else Zscore = (Zscore+score)/2;
X        }
X      zwndw = 20+abs(Zscore/12);
X      beta = score + Bwindow;
X      if (Zscore < score) alpha = Zscore - Awindow - zwndw;
X      else alpha = score - Awindow - zwndw;
X    }
X
X  score = root->score;
X  if (rpt >= 2 || score < -12000) root->flags |= draw;
X  if (iop == 2) return(0);
X  if (Book == NULL) hint = PrVar[2];
X  ElapsedTime(1);
X
X  if (score > -9999 && rpt <= 2)
X    {
X      MakeMove(side,root,&tempb,&tempc,&tempsf,&tempst);
X      algbr(root->f,root->t,root->flags & cstlmask);
X    }
X  else mvstr1[0] = '\0';
X  OutputMove();
X  if (score == -9999 || score == 9998) mate = true;
X  if (mate) hint = 0;
X  if (root->flags & cstlmask) Game50 = GameCnt;
X  else if (board[root->t] == pawn || (root->flags & capture)) 
X    Game50 = GameCnt;
X  GameList[GameCnt].score = score;
X  GameList[GameCnt].nodes = NodeCnt;
X  GameList[GameCnt].time = (short)et;
X  GameList[GameCnt].depth = Sdepth;
X  if (TCflag)
X    {
X      TimeControl.clock[side] -= (et + OperatorTime);
X      if (--TimeControl.moves[side] == 0) SetTimeControl();
X    }
X  if ((root->flags & draw) && bothsides) quit = true;
X  if (GameCnt > 238) quit = true;
X  player = xside;
X  Sdepth = 0;
X  fflush(stdin);
X  return(0);
X}
X
X
XOpeningBook()
X
X/*
X   Go thru each of the opening lines of play and check for a match with 
X   the current game listing. If a match occurs, generate a random number. 
X   If this number is the largest generated so far then the next move in 
X   this line becomes the current "candidate". After all lines are 
X   checked, the candidate move is put at the top of the Tree[] array and 
X   will be played by the program. Note that the program does not handle 
X   book transpositions. 
X*/
X
X{
Xshort j,pnt;
Xunsigned short m,*mp;
Xunsigned r,r0;
Xstruct BookEntry *p;
X
X  srand((unsigned)time0);
X  r0 = m = 0;
X  p = Book;
X  while (p != NULL)
X    {
X      mp = p->mv;
X      for (j = 0; j <= GameCnt; j++)
X        if (GameList[j].gmove != *(mp++)) break;
X      if (j > GameCnt)
X        if ((r=rand()) > r0)
X          {
X            r0 = r; m = *mp;
X            hint = *(++mp);
X          }
X      p = p->next;
X    }
X    
X  for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
X    if ((Tree[pnt].f<<8) + Tree[pnt].t == m) Tree[pnt].score = 0;
X  pick(TrPnt[1],TrPnt[2]-1);
X  if (Tree[TrPnt[1]].score < 0) Book = NULL;
X}
X
X
X#define UpdateSearchStatus\
X{\
X  if (post) ShowCurrentMove(pnt,node->f,node->t);\
X  if (pnt > TrPnt[1])\
X    {\
X      d = best-Zscore; e = best-node->score;\
X      if (best < alpha) ExtraTime = 10*ResponseTime;\
X      else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\
X      else if (d > -zwndw) ExtraTime = 0;\
X      else if (d > -3*zwndw) ExtraTime = ResponseTime;\
X      else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\
X      else ExtraTime = 5*ResponseTime;\
X    }\
X}
X
Xint search(side,ply,depth,alpha,beta,bstline,rpt)
Xshort side,ply,depth,alpha,beta,*rpt;
Xunsigned short bstline[];
X
X/*
X   Perform an alpha-beta search to determine the score for the current 
X   board position. If depth <= 0 only capturing moves, pawn promotions 
X   and responses to check are generated and searched, otherwise all 
X   moves are processed. The search depth is modified for check evasions, 
X   certain re-captures and threats. Extensions may continue for up to 11 
X   ply beyond the nominal search depth. 
X*/
X
X#define prune (cf && score+node->score < alpha)
X#define ReCapture (rcptr && score > alpha && score < beta &&\
X                   ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2] &&\
X                   depth == Sdepth-ply+1)
X#define Parry (hung[side] > 1 && ply == Sdepth+1)
X#define MateThreat (ply < Sdepth+4 && ply > 4 &&\
X                    ChkFlag[ply-2] && ChkFlag[ply-4] &&\
X                    ChkFlag[ply-2] != ChkFlag[ply-4])
X
X{
Xregister short j,pnt;
Xshort best,tempb,tempc,tempsf,tempst;
Xshort xside,pbst,d,e,cf,score,rcnt;
Xunsigned short mv,nxtline[maxdepth];
Xstruct leaf *node,tmp;
X
X  NodeCnt++;
X  xside = otherside[side];
X  
X  if (ply <= Sdepth+3) repetition(rpt); else *rpt = 0;
X  if (*rpt >= 2) return(0);
X
X  score = evaluate(side,xside,ply,depth,alpha,beta);
X  if (score > 9000) return(score);
X  
X  if (depth > 0)
X    {
X      if (InChk || PawnThreat[ply-1] || ReCapture) ++depth;
X    }
X  else
X    {
X      if (score >= alpha &&
X         (InChk || PawnThreat[ply-1] || Parry)) depth = 1;
X      else if (score <= beta && MateThreat) depth = 1;
X    }
X    
X  PV = 0;
X  if (depth > 0 && hashflag && ply > 1)
X    {
X      ProbeTTable(side,depth,&alpha,&beta,&score);
X      bstline[ply] = PV;
X      bstline[ply+1] = 0;
X      if (beta == -20000) return(score);
X      if (alpha > beta) return(alpha);
X    }
X  
X  if (Sdepth == 1) d = 7; else d = 11;
X  if (ply > Sdepth+d || (depth <= 0 && score > beta)) return(score);
X
X  if (ply > 1)
X    if (depth > 0) MoveList(side,ply);
X    else CaptureList(side,xside,ply);
X    
X  if (TrPnt[ply] == TrPnt[ply+1]) return(score);
X    
X  cf = (depth < 1 && ply > Sdepth+1 && !ChkFlag[ply-2] && !slk);
X
X  if (depth > 0) best = -12000; else best = score;
X  if (best > alpha) alpha = best;
X  
X  for (pnt = pbst = TrPnt[ply];
X       pnt < TrPnt[ply+1] && best <= beta;
X       pnt++)
X    {
X      if (ply > 1) pick(pnt,TrPnt[ply+1]-1);
X      node = &Tree[pnt];
X      mv = (node->f << 8) + node->t;
X      nxtline[ply+1] = 0;
X      
X      if (prune) break;
X      if (ply == 1) UpdateSearchStatus;
X
X      if (!(node->flags & exact))
X        {
X          MakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
X          CptrFlag[ply] = (node->flags & capture);
X          PawnThreat[ply] = (node->flags & pwnthrt);
X          Tscore[ply] = node->score;
X          node->score = -search(xside,ply+1,depth-1,-beta,-alpha,
X                                nxtline,&rcnt);
X          if (abs(node->score) > 9000) node->flags |= exact;
X          else if (rcnt == 1) node->score /= 2;
X          if (rcnt >= 2 || GameCnt-Game50 > 99 ||
X             (node->score == 9999-ply && !ChkFlag[ply]))
X            {
X              node->flags |= draw; node->flags |= exact;
X              if (side == computer) node->score = contempt;
X              else node->score = -contempt;
X            }
X          UnmakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
X        }
X      if (node->score > best && !timeout)
X        {
X          if (depth > 0)
X            if (node->score > alpha && !(node->flags & exact))
X              node->score += depth;
X          best = node->score; pbst = pnt;
X          if (best > alpha) alpha = best;
X          for (j = ply+1; nxtline[j] > 0; j++) bstline[j] = nxtline[j];
X          bstline[j] = 0;
X          bstline[ply] = mv;
X          if (ply == 1)
X            {
X              if (best == alpha)
X                {
X                  tmp = Tree[pnt];
X                  for (j = pnt-1; j >= 0; j--) Tree[j+1] = Tree[j];
X                  Tree[0] = tmp;
X                  pbst = 0;
X                }
X              if (Sdepth > 2)
X                if (best > beta) ShowResults(best,bstline,'+');
X                else if (best < alpha) ShowResults(best,bstline,'-');
X                else ShowResults(best,bstline,'&');
X            }
X        }
X      if (NodeCnt > ETnodes) ElapsedTime(0);
X      if (timeout) return(-Tscore[ply-1]);
X    }
X    
X  node = &Tree[pbst];
X  mv = (node->f<<8) + node->t;
X  if (hashflag && ply <= Sdepth && *rpt == 0 && best == alpha)
X    PutInTTable(side,best,depth,alpha,beta,mv);
X  if (depth > 0)
X    {
X      j = (node->f<<6) + node->t; if (side == black) j |= 0x1000;
X      if (history[j] < 150) history[j] += 2*depth;
X      if (node->t != (GameList[GameCnt].gmove & 0xFF))
X        if (best <= beta) killr3[ply] = mv;
X        else if (mv != killr1[ply])
X          {
X            killr2[ply] = killr1[ply];
X            killr1[ply] = mv;
X          }
X      if (best > 9000) killr0[ply] = mv; else killr0[ply] = 0;
X    }
X  return(best);
X}
X
X
Xint evaluate(side,xside,ply,depth,alpha,beta)
Xshort side,xside,ply,depth,alpha,beta;
X
X/*
X   Compute an estimate of the score by adding the positional score from 
X   the previous ply to the material difference. If this score falls 
X   inside a window which is 180 points wider than the alpha-beta window 
X   (or within a 50 point window during quiescence search) call 
X   ScorePosition() to determine a score, otherwise return the estimated 
X   score. If one side has only a king and the other either has no pawns 
X   or no pieces then the function ScoreLoneKing() is called. 
X*/
X
X{
Xregister short evflag;
X
X  Xscore = -Pscore[ply-1] - INCscore + mtl[side] - mtl[xside];
X  hung[white] = hung[black] = 0;
X  slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) ||
X         (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0)));
X  
X  if (slk) evflag = false;
X  else evflag = 
X     (ply == 1 || ply < Sdepth ||
X     (depth == 0 && Xscore > alpha-xwndw && Xscore < beta+xwndw) ||
X     (depth < 0 && Xscore > alpha-25 && Xscore < beta+25));
X    
X  if (evflag)
X    {
X      EvalNodes++;
X      ataks(side,atak[side]);
X      if (atak[side][PieceList[xside][0]] > 0) return(10001-ply);
X      ataks(xside,atak[xside]);
X      InChk = (atak[xside][PieceList[side][0]] > 0);
X      ScorePosition(side,&Xscore);
X    }
X  else
X    {
X      if (SqAtakd(PieceList[xside][0],side)) return(10001-ply);
X      InChk = SqAtakd(PieceList[side][0],xside);
X      if (slk) ScoreLoneKing(side,&Xscore);
X    }
X    
X  Pscore[ply] = Xscore - mtl[side] + mtl[xside];
X  if (InChk) ChkFlag[ply-1] = Pindex[TOsquare];
X  else ChkFlag[ply-1] = 0;
X  return(Xscore);
X}
X
X
XProbeTTable(side,depth,alpha,beta,score)
Xshort side,depth,*alpha,*beta,*score;
X
X/* 
X   Look for the current board position in the transposition table.
X*/
X
X{
Xshort hindx;
X  if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
X  hindx = (hashkey & (ttblsz-1));
X  ptbl = (ttable + hindx);
X  if (ptbl->depth >= depth && ptbl->hashbd == hashbd)
X    {
X      HashCnt++;
X      PV = ptbl->mv;
X      if (ptbl->flags & truescore)
X        {
X          *score = ptbl->score;
X          *beta = -20000;
X          return(true);
X        }
X/*
X      else if (ptbl->flags & upperbound)
X        {
X          if (ptbl->score < *beta) *beta = ptbl->score+1;
X        }
X*/
X      else if (ptbl->flags & lowerbound)
X        {
X          if (ptbl->score > *alpha) *alpha = ptbl->score-1;
X        }
X    }
X  return(false);
X}
X
X
XPutInTTable(side,score,depth,alpha,beta,mv)
Xshort side,score,depth,alpha,beta;
Xunsigned short mv;
X
X/*
X   Store the current board position in the transposition table.
X*/
X
X{
Xshort hindx;
X  if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
X  hindx = (hashkey & (ttblsz-1));
X  ptbl = (ttable + hindx);
X  ptbl->hashbd = hashbd;
X  ptbl->depth = depth;
X  ptbl->score = score; 
X  ptbl->mv = mv;
X  ptbl->flags = 0;
X  if (score < alpha) ptbl->flags |= upperbound;
X  else if (score > beta) ptbl->flags |= lowerbound;
X  else ptbl->flags |= truescore;
X}
X
X
XZeroTTable()
X{
Xint i;
X  if (hashflag)
X    for (i = 0; i < ttblsz; i++)
X      {
X        ptbl = (ttable + i);
X        ptbl->depth = 0;
X      }
X}
X
X
XMoveList(side,ply)
Xshort side,ply;
X
X/*
X   Fill the array Tree[] with all available moves for side to play. Array 
X   TrPnt[ply] contains the index into Tree[] of the first move at a ply. 
X*/
X    
X{
Xregister short i,xside,f;
X
X  xside = otherside[side];
X  if (PV == 0) Swag0 = killr0[ply]; else Swag0 = PV;
X  Swag1 = killr1[ply]; Swag2 = killr2[ply];
X  Swag3 = killr3[ply]; Swag4 = 0;
X  if (ply > 2) Swag4 = killr1[ply-2];
X  TrPnt[ply+1] = TrPnt[ply];
X  Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
X  for (i = PieceCnt[side]; i >= 0; i--)
X    GenMoves(ply,PieceList[side][i],side,xside);
X  if (kingmoved[side] == 0 && !castld[side])
X    {
X      f = PieceList[side][0];
X      if (castle(side,f,f+2,0))
X        {
X          LinkMove(ply,f,f+2,xside);
X          Tree[TrPnt[ply+1]-1].flags |= cstlmask;
X        }
X      if (castle(side,f,f-2,0))
X        {
X          LinkMove(ply,f,f-2,xside);
X          Tree[TrPnt[ply+1]-1].flags |= cstlmask;
X        }
X    }
X}
X
X
XGenMoves(ply,sq,side,xside)
Xshort ply,sq,side,xside;
X
X/*
X   Generate moves for a piece. The from square is mapped onto a special  
X   board and offsets (taken from array Dir[]) are added to the mapped 
X   location. The newly generated square is tested to see if it falls off 
X   the board by ANDing the square with 88 HEX. Legal moves are linked 
X   into the tree. 
X*/
X    
X{
Xregister short m,u,d,i,m0,piece; 
X
X  piece = board[sq]; m0 = map[sq];
X  if (sweep[piece])
X    for (i = Dstart[piece]; i <= Dstop[piece]; i++)
X      {
X        d = Dir[i]; m = m0+d;
X        while (!(m & 0x88))
X          {
X            u = unmap[m];
X            if (color[u] == neutral)
X              {
X                LinkMove(ply,sq,u,xside);
X                m += d;
X              }
X            else if (color[u] == xside)
X              {
X                LinkMove(ply,sq,u,xside);
X                break;
X              }
X            else break;
X          }
X      }
X  else if (piece == pawn)
X    {
X      if (side == white && color[sq+8] == neutral)
X        {
X          LinkMove(ply,sq,sq+8,xside);
X          if (row[sq] == 1)
X            if (color[sq+16] == neutral)
X              LinkMove(ply,sq,sq+16,xside);
X        }
X      else if (side == black && color[sq-8] == neutral)
X        {
X          LinkMove(ply,sq,sq-8,xside);
X          if (row[sq] == 6)
X            if (color[sq-16] == neutral)
X              LinkMove(ply,sq,sq-16,xside);
X        }
X      for (i = Dstart[piece]; i <= Dstop[piece]; i++)
X        if (!((m = m0+Dir[i]) & 0x88))
X          {
X            u = unmap[m];
X            if (color[u] == xside || u == epsquare)
X              LinkMove(ply,sq,u,xside);
X          }
X    }
X  else
X    {
X      for (i = Dstart[piece]; i <= Dstop[piece]; i++)
X        if (!((m = m0+Dir[i]) & 0x88))
X          {
X            u = unmap[m];
X            if (color[u] != side) LinkMove(ply,sq,u,xside);
X          }
X    }
X}
X
X
XLinkMove(ply,f,t,xside)
Xshort ply,f,t,xside;
X
X/*
X   Add a move to the tree.  Assign a bonus to order the moves
X   as follows:
X     1. Principle variation
X     2. Capture of last moved piece
X     3. Other captures (major pieces first)
X     4. Killer moves
X     5. "history" killers    
X*/
X
X{
Xregister short s,z;
Xregister unsigned short mv;
Xstruct leaf *node;
X
X  node = &Tree[TrPnt[ply+1]];
X  ++TrPnt[ply+1];
X  node->flags = 0;
X  node->f = f; node->t = t;
X  mv = (f<<8) + t;
X  s = 0;
X  if (mv == Swag0) s = 2000;
X  else if (mv == Swag1) s = 60;
X  else if (mv == Swag2) s = 50;
X  else if (mv == Swag3) s = 40;
X  else if (mv == Swag4) s = 30;
X  if (color[t] != neutral)
X    {
X      node->flags |= capture;
X      if (t == TOsquare) s += 500;
X      s += value[board[t]] - board[f];
X    }
X  if (board[f] == pawn)
X    if (row[t] == 0 || row[t] == 7)
X      {
X        node->flags |= promote;
X        s += 800;
X      }
X    else if (row[t] == 1 || row[t] == 6)
X      {
X        node->flags |= pwnthrt;
X        s += 600;
X      }
X    else if (t == epsquare) node->flags |= epmask;
X  z = (f<<6) + t; if (xside == white) z |= 0x1000;
X  s += history[z];
X  node->score = s - 20000;
X}
X
X
XCaptureList(side,xside,ply)
Xshort side,xside,ply;
X
X/*
X    Generate captures and Pawn promotions only.
X*/
X
X#define LinkCapture\
X{\
X  node->f = sq; node->t = u;\
X  node->flags = capture;\
X  node->score = value[board[u]] + svalue[board[u]] - piece;\
X  if (piece == pawn && (u < 8 || u > 55))\
X    {\
X      node->flags |= promote;\
X      node->score = valueQ;\
X    }\
X  ++node;\
X  ++TrPnt[ply+1];\
X}
X
X{
Xregister short m,u,d,sq,m0;
Xshort i,j,j1,j2,r7,d0,piece,*PL;
Xstruct leaf *node;
X
X  TrPnt[ply+1] = TrPnt[ply];
X  node = &Tree[TrPnt[ply]];
X  Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
X  if (side == white)
X    {
X      r7 = 6; d0 = 8;
X    }
X  else
X    {
X      r7 = 1; d0 = -8;
X    }
X  PL = PieceList[side];
X  for (i = 0; i <= PieceCnt[side]; i++)
X    { 
X      sq = PL[i];
X      m0 = map[sq]; piece = board[sq];
X      j1 = Dstart[piece]; j2 = Dstop[piece];
X      if (sweep[piece])
X        for (j = j1; j <= j2; j++)
X          {
X            d = Dir[j]; m = m0+d;
X            while (!(m & 0x88))
X              {
X                u = unmap[m];
X                if (color[u] == neutral) m += d;
X                else
X                  {
X                    if (color[u] == xside) LinkCapture;
X                    break;
X                  }
X              }
X          }
X      else
X        {
X          for (j = j1; j <= j2; j++)
X            if (!((m = m0+Dir[j]) & 0x88))
X              {
X                u = unmap[m];
X                if (color[u] == xside) LinkCapture;
X              }
X          if (piece == pawn && row[sq] == r7)
X            {
X              u = sq+d0;
X              if (color[u] == neutral) LinkCapture;
X            }
X        }
X    }
X}
X
X  
Xint castle(side,kf,kt,iop)
Xshort side,kf,kt,iop;
X
X/*
X   Make or Unmake a castling move.
X*/
X
X{
Xregister short rf,rt,d,t0,xside;
X
X  xside = otherside[side];
X  if (kt > kf)
X    {
X      rf = kf+3; rt = kt-1; d = 1;
X    }
X  else
X    {
X      rf = kf-4; rt = kt+1; d = -1;
X    }
X  if (iop == 0)
X    {
X      if (board[kf] != king || board[rf] != rook || color[rf] != side)
X        return(false);
X      if (color[kt] != neutral || color[rt] != neutral) return(false);
X      if (d == -1 && color[kt+d] != neutral) return(false);
X      if (SqAtakd(kf,xside)) return(false);
X      if (SqAtakd(kt,xside)) return(false);
X      if (SqAtakd(kf+d,xside)) return(false);
X    }
X  else
X    {
X      if (iop == 1) castld[side] = true; else castld[side] = false;
X      if (iop == 2)
X        {
X          t0 = kt; kt = kf; kf = t0;
X          t0 = rt; rt = rf; rf = t0;
X        }
X      board[kt] = king; color[kt] = side; Pindex[kt] = 0;
X      board[kf] = no_piece; color[kf] = neutral;
X      board[rt] = rook; color[rt] = side; Pindex[rt] = Pindex[rf];
X      board[rf] = no_piece; color[rf] = neutral;
X      PieceList[side][Pindex[kt]] = kt;
X      PieceList[side][Pindex[rt]] = rt;
X      if (hashflag)
X        {
X          UpdateHashbd(side,king,kf,kt);
X          UpdateHashbd(side,rook,rf,rt);
X        }
X    }
X  return(true);
X}
X
X
XEnPassant(xside,f,t,iop)
Xshort xside,f,t,iop;
X
X/*
X   Make or unmake an en passant move.
X*/
X
X{
Xregister short l;
X  if (t > f) l = t-8; else l = t+8;
X  if (iop == 1)
X    {
X      board[l] = no_piece; color[l] = neutral;
X    }
X  else 
X    {
X      board[l] = pawn; color[l] = xside;
X    }
X  InitializeStats();
X}
X
X
XMakeMove(side,node,tempb,tempc,tempsf,tempst)
Xshort side,*tempc,*tempb,*tempsf,*tempst;
Xstruct leaf *node;
X
X/*
X   Update Arrays board[], color[], and Pindex[] to reflect the new board 
X   position obtained after making the move pointed to by node. Also 
X   update miscellaneous stuff that changes when a move is made. 
X*/
X    
X{
Xregister short f,t,xside,ct,cf;
X
X  xside = otherside[side];
X  f = node->f; t = node->t; epsquare = -1;
X  FROMsquare = f; TOsquare = t;
X  INCscore = 0;
X  GameList[++GameCnt].gmove = (f<<8) + t;
X  if (node->flags & cstlmask)
X    {
X      GameList[GameCnt].piece = no_piece;
X      GameList[GameCnt].color = side;
X      castle(side,f,t,1);
X    }
X  else
X    {
X      *tempc = color[t]; *tempb = board[t];
X      *tempsf = svalue[f]; *tempst = svalue[t];
X      GameList[GameCnt].piece = *tempb;
X      GameList[GameCnt].color = *tempc;
X      if (*tempc != neutral)
X        {
X          UpdatePieceList(*tempc,t,1);
X          if (*tempb == pawn) --PawnCnt[*tempc][column[t]];
X          if (board[f] == pawn)
X            {
X              --PawnCnt[side][column[f]];
X              ++PawnCnt[side][column[t]];
X              cf = column[f]; ct = column[t];
X              if (PawnCnt[side][ct] > 1+PawnCnt[side][cf])
X                INCscore -= 15;
X              else if (PawnCnt[side][ct] < 1+PawnCnt[side][cf])
X                INCscore += 15;
X              else if (ct == 0 || ct == 7 || PawnCnt[side][ct+ct-cf] == 0)
X                INCscore -= 15;
X            }
X          mtl[xside] -= value[*tempb];
X          if (*tempb == pawn) pmtl[xside] -= valueP;
X          if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
X          INCscore += *tempst;
X        }
X      color[t] = color[f]; board[t] = board[f]; svalue[t] = svalue[f];
X      Pindex[t] = Pindex[f]; PieceList[side][Pindex[t]] = t;
X      color[f] = neutral; board[f] = no_piece;
X      if (board[t] == pawn)
X        if (t-f == 16) epsquare = f+8;
X        else if (f-t == 16) epsquare = f-8;
X      if (node->flags & promote)
X        {
X          board[t] = queen;
X          --PawnCnt[side][column[t]];
X          mtl[side] += valueQ - valueP;
X          pmtl[side] -= valueP;
X          HasQueen[side] = true;
X          if (hashflag)
X            {
X              UpdateHashbd(side,pawn,f,-1);
X              UpdateHashbd(side,queen,f,-1);
X            }
X          INCscore -= *tempsf;
X        } 
X      if (board[t] == king) ++kingmoved[side];
X      if (node->flags & epmask) EnPassant(xside,f,t,1);
X      else if (hashflag) UpdateHashbd(side,board[t],f,t);
X    }
X}
X
X
XUnmakeMove(side,node,tempb,tempc,tempsf,tempst)
Xshort side,*tempc,*tempb,*tempsf,*tempst;
Xstruct leaf *node;
X
X/*
X   Take back a move.
X*/
X
X{
Xregister short f,t,xside;
X
X  xside = otherside[side];
X  f = node->f; t = node->t; epsquare = -1;
X  GameCnt--;
X  if (node->flags & cstlmask) castle(side,f,t,2);
X  else
X    {
X      color[f] = color[t]; board[f] = board[t]; svalue[f] = *tempsf;
X      Pindex[f] = Pindex[t]; PieceList[side][Pindex[f]] = f;
X      color[t] = *tempc; board[t] = *tempb; svalue[t] = *tempst;
X      if (node->flags & promote)
X        {
X          board[f] = pawn;
X          ++PawnCnt[side][column[t]];
X          mtl[side] += valueP - valueQ;
X          pmtl[side] += valueP;
X          if (hashflag)
X            {
X              UpdateHashbd(side,queen,-1,t);
X              UpdateHashbd(side,pawn,-1,t);
X            }
X        } 
X      if (*tempc != neutral)
X        {
X          UpdatePieceList(*tempc,t,2);
X          if (*tempb == pawn) ++PawnCnt[*tempc][column[t]];
X          if (board[f] == pawn)
X            {
X              --PawnCnt[side][column[t]];
X              ++PawnCnt[side][column[f]];
X            }
X          mtl[xside] += value[*tempb];
X          if (*tempb == pawn) pmtl[xside] += valueP;
X          if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
X        }
X      if (board[f] == king) --kingmoved[side];
X      if (node->flags & epmask) EnPassant(xside,f,t,2);
X      else if (hashflag) UpdateHashbd(side,board[f],f,t);
X    }
X}
X
X
XUpdateHashbd(side,piece,f,t)
Xshort side,piece,f,t;
X
X/*
X   hashbd contains a 32 bit "signature" of the board position. hashkey 
X   contains a 16 bit code used to address the hash table. When a move is 
X   made, XOR'ing the hashcode of moved piece on the from and to squares 
X   with the hashbd and hashkey values keeps things current. 
X*/
X
X{
X  if (f >= 0)
X    {
X      hashbd ^= hashcode[side][piece][f].bd;
X      hashkey ^= hashcode[side][piece][f].key;
X    }
X  if (t >= 0)
X    {
X      hashbd ^= hashcode[side][piece][t].bd;
X      hashkey ^= hashcode[side][piece][t].key;
X    }
X}
X
X
XUpdatePieceList(side,sq,iop)
Xshort side,sq,iop;
X
X/*
X   Update the PieceList and Pindex arrays when a piece is captured or 
X   when a capture is unmade. 
X*/
X
X{
Xregister short i;
X  if (iop == 1)
X    {
X      PieceCnt[side]--;
X      for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
X        {
X          PieceList[side][i] = PieceList[side][i+1];
X          Pindex[PieceList[side][i]] = i;
X        }
X    }
X  else
X    {
X      PieceCnt[side]++;
X      PieceList[side][PieceCnt[side]] = sq;
X      Pindex[sq] = PieceCnt[side];
X    }
X}
X
X
XInitializeStats()
X
X/*
X   Scan thru the board seeing what's on each square. If a piece is found, 
X   update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also 
X   determine the material for each side and set the hashkey and hashbd 
X   variables to represent the current board position. Array 
X   PieceList[side][indx] contains the location of all the pieces of 
X   either side. Array Pindex[sq] contains the indx into PieceList for a 
X   given square. 
X*/
X
X{
Xregister short i,sq;
X  epsquare = -1;
X  for (i = 0; i < 8; i++)
X    PawnCnt[white][i] = PawnCnt[black][i] = 0;
X  mtl[white] = mtl[black] = pmtl[white] = pmtl[black] = 0;
X  PieceCnt[white] = PieceCnt[black] = 0;
X  hashbd = hashkey = 0;
X  for (sq = 0; sq < 64; sq++)
X    if (color[sq] != neutral)
X      {
X        mtl[color[sq]] += value[board[sq]];
X        if (board[sq] == pawn)
X          {
X            pmtl[color[sq]] += valueP;
X            ++PawnCnt[color[sq]][column[sq]];
X          }
X        if (board[sq] == king) Pindex[sq] = 0;
X          else Pindex[sq] = ++PieceCnt[color[sq]];
X        PieceList[color[sq]][Pindex[sq]] = sq;
X        hashbd ^= hashcode[color[sq]][board[sq]][sq].bd;
X        hashkey ^= hashcode[color[sq]][board[sq]][sq].key;
X      }
X}
X
X
Xpick(p1,p2)
Xshort p1,p2;
X
X/*  
X   Find the best move in the tree between indexes p1 and p2. Swap the 
X   best move into the p1 element. 
X*/
X
X{
Xregister short p,s,p0,s0;
Xstruct leaf temp;
X
X  s0 = Tree[p1].score; p0 = p1;
X  for (p = p1+1; p <= p2; p++)
X    if ((s = Tree[p].score) > s0)
X      {
X        s0 = s; p0 = p;
X      }
X  if (p0 != p1)
X    {
X      temp = Tree[p1]; Tree[p1] = Tree[p0]; Tree[p0] = temp;
X    }
X}
X
X
Xrepetition(cnt)
Xshort *cnt;
X
X/*
X    Check for draw by threefold repetition.
X*/
X
X{
Xregister short i,c,f,t;
Xshort b[64];
Xunsigned short m;
X  *cnt = c = 0;
X  if (GameCnt > Game50+3)
X    {
X      for (i = 0; i < 64; b[i++] = 0);
X      for (i = GameCnt; i > Game50; i--)
X        {
X          m = GameList[i].gmove; f = m>>8; t = m & 0xFF;
X          if (++b[f] == 0) c--; else c++;
X          if (--b[t] == 0) c--; else c++;
X          if (c == 0) (*cnt)++;
X        }
X    }
X}
X
X
Xint SqAtakd(sq,side)
Xshort sq,side;
X
X/*
X  See if any piece with color 'side' ataks sq.  First check for pawns
X  or king, then try other pieces. Array Dcode is used to check for
X  knight attacks or R,B,Q co-linearity.  
X*/
X
X{
Xregister short m,d,m0,m1,i,loc,piece,*PL;
X
X  m1 = map[sq];
X  if (side == white) m = m1-0x0F; else m = m1+0x0F;
X  if (!(m & 0x88))
X    if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
X  if (side == white) m = m1-0x11; else m = m1+0x11;
X  if (!(m & 0x88))
X    if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
X  if (distance(sq,PieceList[side][0]) == 1) return(true);
X  
X  PL = PieceList[side];
X  for (i = 1; i <= PieceCnt[side]; i++)
X    {
X      loc = PL[i]; piece = board[loc];
X      if (piece == pawn) continue;
X      m0 = map[loc]; d = Dcode[abs(m1-m0)];
X      if (d == 0 || (Pdir[d] & pbit[piece]) == 0) continue;
X      if (piece == knight) return(true);
X      else
X        {
X          if (m1 < m0) d = -d;
X          for (m = m0+d; m != m1; m += d)
X            if (color[unmap[m]] != neutral) break;
X          if (m == m1) return(true);
X        }
X    }
X  return(false);
X}
X
X
Xataks(side,a)
Xshort side,*a;
X
X/*
X    Fill array atak[][] with info about ataks to a square.  Bits 8-15
X    are set if the piece (king..pawn) ataks the square. Bits 0-7
X    contain a count of total ataks to the square.
X*/
X
X{
Xregister short u,m,d,c,m0;
Xshort j,j1,j2,piece,i,sq,*PL;
X 
X  for (u = 0; u < 64; a[u++] = 0); 
X  Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
X  PL = PieceList[side];
X  for (i = 0; i <= PieceCnt[side]; i++)
X    {
X      sq = PL[i];
X      m0 = map[sq];
X      piece = board[sq];
X      c = control[piece]; j1 = Dstart[piece]; j2 = Dstop[piece];
X      if (sweep[piece])
X        for (j = j1; j <= j2; j++)
X          {
X            d = Dir[j]; m = m0+d;
X            while (!(m & 0x88))
X              {
X                u = unmap[m];
X                a[u] = ++a[u] | c;
X                if (color[u] == neutral) m += d;
X                else break;
X              }
X          }
X      else
X        for (j = j1; j <= j2; j++)
X          if (!((m = m0+Dir[j]) & 0x88))
X            {
X              u = unmap[m];
X              a[u] = ++a[u] | c;
X            }
X    }
X}
X
END_OF_gnuchess.c1
if test 44471 -ne `wc -c <gnuchess.c1`; then
    echo shar: \"gnuchess.c1\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 4\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0