summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHristo Kovachev <bger@rockbox.org>2006-02-22 14:24:54 +0000
committerHristo Kovachev <bger@rockbox.org>2006-02-22 14:24:54 +0000
commit91522721f4a6f4449e14e1b3ccb9f6f2add5d814 (patch)
treedbb2ee4d9e4ee752f8eaf6081204be2f44f20fa8
parentb12bcecb297ab8408b25bc9e539d78fa92e6589e (diff)
downloadrockbox-91522721f4a6f4449e14e1b3ccb9f6f2add5d814.zip
rockbox-91522721f4a6f4449e14e1b3ccb9f6f2add5d814.tar.gz
rockbox-91522721f4a6f4449e14e1b3ccb9f6f2add5d814.tar.bz2
rockbox-91522721f4a6f4449e14e1b3ccb9f6f2add5d814.tar.xz
New chessbox plugin by Miguel A. ArГ©valo, based on GNU Chess v2
Not built yet because of a missing dependancy with the pieces' bitmaps. Someone with Makefile knowledge, please, look at it! git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8778 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/bitmaps/native/SOURCES13
-rw-r--r--apps/plugins/bitmaps/native/chessbox_pieces.128x128x1.bmpbin0 -> 1726 bytes
-rw-r--r--apps/plugins/bitmaps/native/chessbox_pieces.128x128x2.bmpbin0 -> 7734 bytes
-rw-r--r--apps/plugins/bitmaps/native/chessbox_pieces.176x176x16.bmpbin0 -> 38950 bytes
-rw-r--r--apps/plugins/bitmaps/native/chessbox_pieces.240x240x16.bmpbin0 -> 25526 bytes
-rw-r--r--apps/plugins/bitmaps/native/chessbox_pieces.64x64x1.bmpbin0 -> 894 bytes
-rw-r--r--apps/plugins/chessbox/Makefile112
-rw-r--r--apps/plugins/chessbox/chessbox.c485
-rw-r--r--apps/plugins/chessbox/gnuchess.c2405
-rw-r--r--apps/plugins/chessbox/gnuchess.h37
-rw-r--r--docs/CREDITS1
11 files changed, 3053 insertions, 0 deletions
diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES
index 380022c..bd1a5cb 100644
--- a/apps/plugins/bitmaps/native/SOURCES
+++ b/apps/plugins/bitmaps/native/SOURCES
@@ -17,6 +17,19 @@ bejeweled_jewels.220x176x16.bmp
bejeweled_jewels.320x240x16.bmp
#endif
+/* ChessBox */
+#if (LCD_WIDTH >= 240) && (LCD_HEIGHT >= 240) & (LCD_DEPTH >= 16)
+chessbox_pieces.240x240x16.bmp
+#elif (LCD_WIDTH >= 176) && (LCD_HEIGHT >= 176) & (LCD_DEPTH >= 16)
+chessbox_pieces.176x176x16.bmp
+#elif (LCD_WIDTH >= 128) && (LCD_HEIGHT >= 128) & (LCD_DEPTH > 1)
+chessbox_pieces.128x128x2.bmp
+#elif (LCD_WIDTH >= 128) && (LCD_HEIGHT >= 128)
+chessbox_pieces.128x128x1.bmp
+#elif (LCD_WIDTH >= 64) && (LCD_HEIGHT >= 64)
+chessbox_pieces.64x64x1.bmp
+#endif
+
/* Solitaire */
#ifdef HAVE_LCD_COLOR
solitaire_cardback.220x176x16.bmp
diff --git a/apps/plugins/bitmaps/native/chessbox_pieces.128x128x1.bmp b/apps/plugins/bitmaps/native/chessbox_pieces.128x128x1.bmp
new file mode 100644
index 0000000..967645e
--- /dev/null
+++ b/apps/plugins/bitmaps/native/chessbox_pieces.128x128x1.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/chessbox_pieces.128x128x2.bmp b/apps/plugins/bitmaps/native/chessbox_pieces.128x128x2.bmp
new file mode 100644
index 0000000..85b7457
--- /dev/null
+++ b/apps/plugins/bitmaps/native/chessbox_pieces.128x128x2.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/chessbox_pieces.176x176x16.bmp b/apps/plugins/bitmaps/native/chessbox_pieces.176x176x16.bmp
new file mode 100644
index 0000000..ab876a4
--- /dev/null
+++ b/apps/plugins/bitmaps/native/chessbox_pieces.176x176x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/chessbox_pieces.240x240x16.bmp b/apps/plugins/bitmaps/native/chessbox_pieces.240x240x16.bmp
new file mode 100644
index 0000000..c08c619
--- /dev/null
+++ b/apps/plugins/bitmaps/native/chessbox_pieces.240x240x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/chessbox_pieces.64x64x1.bmp b/apps/plugins/bitmaps/native/chessbox_pieces.64x64x1.bmp
new file mode 100644
index 0000000..fbd46ee
--- /dev/null
+++ b/apps/plugins/bitmaps/native/chessbox_pieces.64x64x1.bmp
Binary files differ
diff --git a/apps/plugins/chessbox/Makefile b/apps/plugins/chessbox/Makefile
new file mode 100644
index 0000000..3d9f024
--- /dev/null
+++ b/apps/plugins/chessbox/Makefile
@@ -0,0 +1,112 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+
+INCLUDES = -I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \
+ -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) -I$(BUILDDIR)
+CFLAGS = $(GCCOPTS) -O3 $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \
+ -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN
+
+ifdef APPEXTRA
+ INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
+endif
+
+LINKFILE := $(OBJDIR)/link.lds
+DEPFILE = $(OBJDIR)/dep-chessbox
+SRC = chessbox.c gnuchess.c
+
+SOURCES = $(SRC)
+OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
+DIRS = .
+
+LDS := ../plugin.lds
+OUTPUT = $(OUTDIR)/chessbox.rock
+
+all: $(OUTPUT)
+
+ifndef SIMVER
+$(OBJDIR)/chessbox.elf: $(OBJS) $(LINKFILE)
+ @echo "LD "`basename $@`
+ @$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \
+ -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/chessbox.map
+
+$(OUTPUT): $(OBJDIR)/chessbox.elf
+ @echo "OBJCOPY "`basename $@`
+ @$(OC) -O binary $< $@
+else
+
+ifeq ($(SIMVER), x11)
+###################################################
+# This is the X11 simulator version
+
+$(OUTPUT): $(OBJS)
+ @echo "LD $<"
+ @$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin -o $@
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
+# 'x' must be kept or you'll have "Win32 error 5"
+# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
+# #define ERROR_ACCESS_DENIED 5L
+else
+ @chmod -x $@
+endif
+
+else # end of x11-simulator
+ifeq ($(SIMVER), sdl)
+###################################################
+# This is the SDL simulator version
+
+$(OUTPUT): $(OBJS)
+ @echo "LD $<"
+ @$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin -o $@
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
+# 'x' must be kept or you'll have "Win32 error 5"
+# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
+# #define ERROR_ACCESS_DENIED 5L
+else
+ @chmod -x $@
+endif
+
+else # end of sdl-simulator
+###################################################
+# This is the win32 simulator version
+DLLTOOLFLAGS = --export-all
+DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin
+
+$(OUTPUT): $(OBJS)
+ @echo "DLL "`basename $@`
+ @$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS)
+ @$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \
+ $(BUILDDIR)/libplugin.a -o $@
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
+# 'x' must be kept or you'll have "Win32 error 5"
+# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
+# #define ERROR_ACCESS_DENIED 5L
+else
+ @chmod -x $@
+endif
+endif # end of win32-simulator
+endif
+endif # end of simulator section
+
+
+include $(TOOLSDIR)/make.inc
+
+# MEMORYSIZE should be passed on to this makefile with the chosen memory size
+# given in number of MB
+$(LINKFILE): $(LDS)
+ @echo "build "`basename $@`
+ @cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) \
+ $(DEFINES) -E -P - >$@
+
+clean:
+ @echo "cleaning chessbox"
+ @rm -rf $(OBJDIR)/chessbox
+ @rm -f $(OBJDIR)/chessbox.* $(DEPFILE)
+
+-include $(DEPFILE)
+
diff --git a/apps/plugins/chessbox/chessbox.c b/apps/plugins/chessbox/chessbox.c
new file mode 100644
index 0000000..60dff81
--- /dev/null
+++ b/apps/plugins/chessbox/chessbox.c
@@ -0,0 +1,485 @@
+/***************************************************************************
+* __________ __ ___.
+* Open \______ \ ____ ____ | | _\_ |__ _______ ___
+* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+* \/ \/ \/ \/ \/
+*
+* Copyright (C) 2006 Miguel A. Arévalo
+* Color graphics from eboard
+* GNUChess v2 chess engine Copyright (c) 1988 John Stanback
+*
+* All files in this archive are subject to the GNU General Public License.
+* See the file COPYING in the source tree root for full license agreement.
+*
+* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+* KIND, either express or implied.
+*
+****************************************************************************/
+
+#include "plugin.h"
+
+#ifdef HAVE_LCD_BITMAP
+
+#include "gnuchess.h"
+
+/* type definitions */
+struct cb_command {
+ int type;
+ char mv_s[5];
+ unsigned short mv;
+};
+
+/* global rockbox api */
+static struct plugin_api* rb;
+
+/* External bitmaps */
+extern const fb_data chessbox_pieces[];
+
+
+PLUGIN_HEADER
+
+/* button definitions */
+#if (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
+#define CB_SELECT BUTTON_SELECT
+#define CB_UP BUTTON_SCROLL_BACK
+#define CB_DOWN BUTTON_SCROLL_FWD
+#define CB_LEFT BUTTON_LEFT
+#define CB_RIGHT BUTTON_RIGHT
+#define CB_PLAY BUTTON_PLAY
+#define CB_LEVEL BUTTON_MENU
+#define CB_QUIT BUTTON_REL
+
+#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
+#define CB_SELECT BUTTON_MENU
+#define CB_UP BUTTON_UP
+#define CB_DOWN BUTTON_DOWN
+#define CB_LEFT BUTTON_LEFT
+#define CB_RIGHT BUTTON_RIGHT
+#define CB_PLAY BUTTON_PLAY
+#define CB_LEVEL BUTTON_REC
+#define CB_QUIT BUTTON_POWER
+
+#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
+#define CB_SELECT BUTTON_SELECT
+#define CB_UP BUTTON_UP
+#define CB_DOWN BUTTON_DOWN
+#define CB_LEFT BUTTON_LEFT
+#define CB_RIGHT BUTTON_RIGHT
+#define CB_PLAY BUTTON_ON
+#define CB_LEVEL BUTTON_MODE
+#define CB_QUIT BUTTON_OFF
+
+#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
+#define CB_SELECT BUTTON_SELECT
+#define CB_UP BUTTON_UP
+#define CB_DOWN BUTTON_DOWN
+#define CB_LEFT BUTTON_LEFT
+#define CB_RIGHT BUTTON_RIGHT
+#define CB_PLAY BUTTON_PLAY
+#define CB_LEVEL BUTTON_EQ
+#define CB_QUIT BUTTON_MODE
+
+#elif CONFIG_KEYPAD == RECORDER_PAD
+#define CB_SELECT BUTTON_PLAY
+#define CB_UP BUTTON_UP
+#define CB_DOWN BUTTON_DOWN
+#define CB_LEFT BUTTON_LEFT
+#define CB_RIGHT BUTTON_RIGHT
+#define CB_PLAY BUTTON_ON
+#define CB_LEVEL BUTTON_F1
+#define CB_QUIT BUTTON_OFF
+
+#elif CONFIG_KEYPAD == ONDIO_PAD
+#define CB_SELECT (BUTTON_MENU|BUTTON_REL)
+#define CB_UP BUTTON_UP
+#define CB_DOWN BUTTON_DOWN
+#define CB_LEFT BUTTON_LEFT
+#define CB_RIGHT BUTTON_RIGHT
+#define CB_PLAY BUTTON_MENU
+#define CB_LEVEL (BUTTON_MENU|BUTTON_OFF)
+#define CB_QUIT BUTTON_OFF
+
+#else
+ #error CHESSBOX: Unsupported keypad
+#endif
+
+/* use 30x30 tiles */
+#if (LCD_HEIGHT >= 240) && (LCD_WIDTH >= 240)
+#define TILE_WIDTH 30
+#define TILE_HEIGHT 30
+/* use 22x22 tiles */
+#elif (LCD_HEIGHT >= 176) && (LCD_WIDTH >= 176)
+#define TILE_WIDTH 22
+#define TILE_HEIGHT 22
+/* use 16x16 tiles */
+#elif (LCD_HEIGHT >= 128) && (LCD_WIDTH >= 128)
+#define TILE_WIDTH 16
+#define TILE_HEIGHT 16
+/* use 8x8 tiles */
+#elif (LCD_HEIGHT >= 64) && (LCD_WIDTH >= 64)
+#define TILE_WIDTH 8
+#define TILE_HEIGHT 8
+#else
+ #error BEJEWELED: Unsupported LCD
+#endif
+
+/* Calculate Offsets */
+#define XOFS ((LCD_WIDTH-8*TILE_WIDTH)/2)
+#define YOFS ((LCD_HEIGHT-8*TILE_HEIGHT)/2)
+
+/* commands enum */
+#define COMMAND_MOVE 1
+#define COMMAND_PLAY 2
+#define COMMAND_LEVEL 3
+/*#define COMMAND_RESTART 4*/
+#define COMMAND_QUIT 5
+
+/* ---- Get the board column and row (e2 f.e.) for a physical x y ---- */
+void xy2cr ( short x, short y, short *c, short *r ) {
+ if (computer == black ) {
+ *c = x ;
+ *r = y ;
+ } else {
+ *c = 7 - x ;
+ *r = 7 - y ;
+ }
+}
+
+/* ---- get physical x y for a board column and row (e2 f.e.) ---- */
+void cr2xy ( short c, short r, short *x, short *y ) {
+ if ( computer == black ) {
+ *x = c ;
+ *y = r ;
+ } else {
+ *x = 7 - c ;
+ *y = 7 - r ;
+ }
+}
+
+/* ---- Draw a complete board ---- */
+static void cb_drawboard (void) {
+ short r , c , x , y ;
+ short l , piece , p_color ;
+ int b_color=1;
+
+ rb->lcd_clear_display();
+
+ for (r = 0; r < 8; r++) {
+ for (c = 0; c < 8; c++) {
+ l = locn[r][c];
+ piece = board[l] ;
+ p_color = color[l] ;
+ cr2xy ( c , r , &x , &y );
+ if ( piece == no_piece ) {
+ rb->lcd_bitmap_part ( chessbox_pieces , 0 ,
+ TILE_HEIGHT * b_color ,
+ TILE_WIDTH ,
+ XOFS + x*TILE_WIDTH ,
+ YOFS + ( 7 - y )*TILE_HEIGHT ,
+ TILE_WIDTH ,
+ TILE_HEIGHT );
+ } else {
+ rb->lcd_bitmap_part ( chessbox_pieces ,
+ 0 ,
+ 2 * TILE_HEIGHT +
+ 4 * TILE_HEIGHT * ( piece - 1 ) +
+ 2 * TILE_HEIGHT * p_color +
+ TILE_HEIGHT * b_color ,
+ TILE_WIDTH ,
+ XOFS + x*TILE_WIDTH ,
+ YOFS + (7 - y)*TILE_HEIGHT ,
+ TILE_WIDTH ,
+ TILE_HEIGHT );
+ }
+ b_color = (b_color == 1) ? 0 : 1 ;
+ }
+ b_color = (b_color == 1) ? 0 : 1 ;
+ }
+
+ /* draw board limits */
+ if ( LCD_WIDTH > TILE_WIDTH*8 ) {
+ rb->lcd_set_drawmode ( DRMODE_FG );
+ rb->lcd_drawline ( XOFS - 1 , YOFS ,
+ XOFS - 1 , YOFS + TILE_HEIGHT*8 );
+ rb->lcd_drawline ( XOFS + 8*TILE_WIDTH , YOFS ,
+ XOFS + 8*TILE_WIDTH , YOFS + TILE_HEIGHT*8 );
+ }
+ if ( LCD_HEIGHT > TILE_HEIGHT*8 ) {
+ rb->lcd_set_drawmode ( DRMODE_FG );
+ rb->lcd_drawline ( XOFS , YOFS - 1 ,
+ XOFS + TILE_WIDTH*8 , YOFS - 1 );
+ rb->lcd_drawline ( XOFS , YOFS + TILE_HEIGHT*8 ,
+ XOFS + 8*TILE_WIDTH , YOFS + TILE_HEIGHT*8 );
+ }
+ rb->lcd_update();
+}
+
+/* ---- Switch mark on board ---- */
+void cb_switch ( short x , short y ) {
+ rb->lcd_set_drawmode ( DRMODE_COMPLEMENT );
+ rb->lcd_drawrect ( XOFS + x*TILE_WIDTH + 1 ,
+ YOFS + ( 7 - y )*TILE_HEIGHT +1 ,
+ TILE_WIDTH-2 , TILE_HEIGHT-2 );
+ rb->lcd_update();
+}
+
+/* ---- increase playing level ---- */
+void cb_levelup ( void ) {
+ Level ++;
+ if ( Level == 8 ) Level = 1;
+ switch (Level) {
+ case 1 :
+ TCmoves = 60;
+ TCminutes = 5;
+ rb->splash ( 50 , true , "Level 1: 60 moves / 5 min" );
+ break;
+ case 2 :
+ TCmoves = 60;
+ TCminutes = 15;
+ rb->splash ( 50 , true , "Level 2: 60 moves / 15 min" );
+ break;
+ case 3 :
+ TCmoves = 60;
+ TCminutes = 30;
+ rb->splash ( 50 , true , "Level 3: 60 moves / 30 min" );
+ break;
+ case 4 :
+ TCmoves = 40;
+ TCminutes = 30;
+ rb->splash ( 50 , true , "Level 4: 40 moves / 30 min" );
+ break;
+ case 5 :
+ TCmoves = 40;
+ TCminutes = 60;
+ rb->splash ( 50 , true , "Level 5: 40 moves / 60 min" );
+ break;
+ case 6 :
+ TCmoves = 40;
+ TCminutes = 120;
+ rb->splash ( 50 , true , "Level 6: 40 moves / 120 min" );
+ break;
+ case 7 :
+ TCmoves = 40;
+ TCminutes = 240;
+ rb->splash ( 50 , true , "Level 7: 40 moves / 240 min" );
+ break;
+ case 8 :
+ TCmoves = 1;
+ TCminutes = 15;
+ rb->splash ( 50 , true , "Level 8: 1 move / 15 min" );
+ break;
+ case 9 :
+ TCmoves = 1;
+ TCminutes = 60;
+ rb->splash ( 50 , true , "Level 9: 1 move / 60 min" );
+ break;
+ case 10 :
+ TCmoves = 1;
+ TCminutes = 600;
+ rb->splash ( 50 , true , "Level 10: 1 move / 600 min" );
+ break;
+ }
+ TCflag = (TCmoves > 1);
+ SetTimeControl();
+};
+
+/* ---- main user loop ---- */
+struct cb_command cb_getcommand (void) {
+ static short x = 4 , y = 4 ;
+ short c , r , l;
+ int button = BUTTON_NONE;
+ int marked = false , from_marked = false ;
+ short marked_x = 0 , marked_y = 0 ;
+ struct cb_command result;
+
+ cb_switch ( x , y );
+ /* main loop */
+ while ( true ) {
+ button = rb->button_get(true);
+ switch (button) {
+ case CB_QUIT:
+ result.type = COMMAND_QUIT;
+ return result;
+/* case CB_RESTART:
+ result.type = COMMAND_RESTART;
+ return result;*/
+ case CB_LEVEL:
+ result.type = COMMAND_LEVEL;
+ return result;
+ case CB_PLAY:
+ result.type = COMMAND_PLAY;
+ return result;
+ case CB_UP:
+ if ( !from_marked ) cb_switch ( x , y );
+ y++;
+ if ( y == 8 ) {
+ y = 0;
+ x--;
+ if ( x < 0 ) x = 7;
+ }
+ if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
+ from_marked = true ;
+ } else {
+ from_marked = false ;
+ cb_switch ( x , y );
+ }
+ break;
+ case CB_DOWN:
+ if ( !from_marked ) cb_switch ( x , y );
+ y--;
+ if ( y < 0 ) {
+ y = 7;
+ x++;
+ if ( x == 8 ) x = 0;
+ }
+ if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
+ from_marked = true ;
+ } else {
+ from_marked = false ;
+ cb_switch ( x , y );
+ }
+ break;
+ case CB_LEFT:
+ if ( !from_marked ) cb_switch ( x , y );
+ x--;
+ if ( x < 0 ) {
+ x = 7;
+ y++;
+ if ( y == 8 ) y = 0;
+ }
+ if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
+ from_marked = true ;
+ } else {
+ from_marked = false ;
+ cb_switch ( x , y );
+ }
+ break;
+ case CB_RIGHT:
+ if ( !from_marked ) cb_switch ( x , y );
+ x++;
+ if ( x == 8 ) {
+ x = 0;
+ y--;
+ if ( y < 0 ) y = 7;
+ }
+ if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
+ from_marked = true ;
+ } else {
+ from_marked = false ;
+ cb_switch ( x , y );
+ }
+ break;
+ case CB_SELECT:
+ if ( !marked ) {
+ xy2cr ( x , y , &c , &r );
+ l = locn[r][c];
+ if ( ( color[l]!=computer ) && ( board[l]!=no_piece ) ) {
+ marked = true;
+ from_marked = true ;
+ marked_x = x;
+ marked_y = y;
+ }
+ } else {
+ if ( ( marked_x == x ) && ( marked_y == y ) ) {
+ marked = false;
+ from_marked = false;
+ } else {
+ xy2cr ( marked_x , marked_y , &c , &r );
+ result.mv_s[0] = 'a' + c;
+ result.mv_s[1] = '1' + r;
+ xy2cr ( x , y , &c , &r );
+ result.mv_s[2] = 'a' + c;
+ result.mv_s[3] = '1' + r;
+ result.mv_s[4] = '\00';
+ result.type = COMMAND_MOVE;
+ return result;
+ }
+ }
+ break;
+ }
+ }
+
+}
+
+/*****************************************************************************
+* plugin entry point.
+******************************************************************************/
+enum plugin_status plugin_start(struct plugin_api* api, void* parameter) {
+ struct cb_command command;
+ /* init status */
+ bool exit = false;
+
+ /* plugin init */
+ (void)parameter;
+ rb = api;
+ /* end of plugin init */
+
+ /* load opening book, soon */
+
+ /* init board */
+ GNUChess_Initialize();
+
+ /* draw the board */
+ /* I don't like configscreens, start game inmediatly */
+ cb_drawboard();
+
+ while (!exit) {
+ if ( mate ) {
+ rb->splash ( 500 , true , "Checkmate!" );
+ rb->button_get(true);
+ GNUChess_Initialize();
+ cb_drawboard();
+ }
+ command = cb_getcommand ();
+ switch (command.type) {
+ case COMMAND_MOVE:
+ if ( ! VerifyMove ( command.mv_s , 0 , &command.mv ) ) {
+ rb->splash ( 50 , true , "Illegal move!" );
+ cb_drawboard();
+ } else {
+ cb_drawboard();
+ rb->splash ( 0 , true , "Thinking..." );
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost ( true );
+#endif
+ SelectMove ( computer , 0 );
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost ( false );
+#endif
+ cb_drawboard();
+ }
+ break;
+/* case COMMAND_RESTART:
+ GNUChess_Initialize();
+ cb_drawboard();
+ break;*/
+ case COMMAND_PLAY:
+ opponent = !opponent; computer = !computer;
+ rb->splash ( 0 , true , "Thinking..." );
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost ( true );
+#endif
+ SelectMove ( computer , 0 );
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost ( false );
+#endif
+ cb_drawboard();
+ break;
+ case COMMAND_LEVEL:
+ cb_levelup ( );
+ cb_drawboard();
+ break;
+ case COMMAND_QUIT:
+ /*cb_saveposition();*/
+ exit = true;
+ break;
+ }
+ }
+
+ rb->lcd_setfont(FONT_UI);
+ return PLUGIN_OK;
+}
+
+#endif /* HAVE_LCD_BITMAP */
diff --git a/apps/plugins/chessbox/gnuchess.c b/apps/plugins/chessbox/gnuchess.c
new file mode 100644
index 0000000..ed4a7f2
--- /dev/null
+++ b/apps/plugins/chessbox/gnuchess.c
@@ -0,0 +1,2405 @@
+/*
+ C source for CHESS.
+
+ Revision: 5-23-88
+
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+ Copyright (c) 1988 John Stanback
+
+ This file is part of CHESS.
+
+ CHESS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY. No author or distributor
+ accepts responsibility to anyone for the consequences of using it
+ or for whether it serves any particular purpose or works at all,
+ unless he says so in writing. Refer to the CHESS General Public
+ License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute
+ CHESS, but only under the conditions described in the
+ CHESS General Public License. A copy of this license is
+ supposed to have been given to you along with CHESS so you
+ can know your rights and responsibilities. It should be in a
+ file named COPYING. Among other things, the copyright notice
+ and this notice must be preserved on all copies.
+*/
+
+#include "plugin.h"
+
+#include "gnuchess.h"
+
+#include <ctype.h>
+
+#define ttblsz 4096
+
+/*#define ttblsz 16384*/
+#define huge
+
+#define ctlP 0x4000
+#define ctlN 0x2800
+#define ctlB 0x1800
+#define ctlR 0x0400
+#define ctlQ 0x0200
+#define ctlK 0x0100
+#define ctlBQ 0x1200
+#define ctlRQ 0x0600
+#define ctlNN 0x2000
+#define pxx " PNBRQK"
+#define qxx " pnbrqk"
+#define rxx "12345678"
+#define cxx "abcdefgh"
+#define check 0x0001
+#define capture 0x0002
+#define draw 0x0004
+#define promote 0x0008
+#define cstlmask 0x0010
+#define epmask 0x0020
+#define exact 0x0040
+#define pwnthrt 0x0080
+#define truescore 0x0001
+#define lowerbound 0x0002
+#define upperbound 0x0004
+#define maxdepth 30
+#define true 1
+#define false 0
+#define absv(x) ((x) < 0 ? -(x) : (x))
+#define taxicab(a,b) (abs(column[a]-column[b]) + abs(row[a]-row[b]))
+
+/* ---- RockBox datatypes and variables */
+static struct plugin_api* rb;
+
+/* ---- Chess datatypes and variables ---- */
+struct leaf
+ {
+ short f,t,score,reply;
+ unsigned short flags;
+ };
+struct GameRec
+ {
+ unsigned short gmove;
+ short score,depth,time,piece,color;
+ long nodes;
+ };
+struct TimeControlRec
+ {
+ short moves[2];
+ long clock[2];
+ };
+struct BookEntry
+ {
+ struct BookEntry *next;
+ unsigned short *mv;
+ };
+struct hashval
+ {
+ unsigned long bd;
+ unsigned short key;
+ };
+struct hashentry
+ {
+ unsigned long hashbd;
+ unsigned short mv,flags;
+ short score,depth;
+ };
+
+char mvstr1[5],mvstr2[5],mvstr3[6];
+struct leaf Tree[1500],*root;
+short TrPnt[maxdepth],board[64],color[64];
+short row[64],column[64],locn[8][8],Pindex[64],svalue[64];
+short PieceList[2][16],PieceCnt[2],atak[2][64],PawnCnt[2][8];
+short castld[2],kingmoved[2],mtl[2],pmtl[2],emtl[2],hung[2];
+short c1,c2,*atk1,*atk2,*PC1,*PC2,EnemyKing;
+short mate,post,opponent,computer,Sdepth,Awindow,Bwindow,dither;
+long ResponseTime,ExtraTime,Level,et,et0,time0,cputimer,ft;
+long NodeCnt,evrate,ETnodes,EvalNodes,HashCnt;
+short quit,reverse,bothsides,hashflag,InChk,player,force,easy,beep;
+short wking,bking,FROMsquare,TOsquare,timeout,Zscore,zwndw,xwndw,slk;
+short INCscore;
+short HasPawn[2],HasKnight[2],HasBishop[2],HasRook[2],HasQueen[2];
+short ChkFlag[maxdepth],CptrFlag[maxdepth],PawnThreat[maxdepth];
+short Pscore[maxdepth],Tscore[maxdepth],Threat[maxdepth];
+struct GameRec GameList[240];
+short GameCnt,Game50,epsquare,lpost,rcptr,contempt;
+short MaxSearchDepth,Xscore;
+struct BookEntry *Book;
+struct TimeControlRec TimeControl;
+short TCflag,TCmoves,TCminutes,OperatorTime;
+short otherside[3]={1,0,2};
+short rank7[3]={6,1,0};
+short map[64]=
+ {0,1,2,3,4,5,6,7,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77};
+short unmap[120]=
+ {0,1,2,3,4,5,6,7,-1,-1,-1,-1,-1,-1,-1,-1,
+ 8,9,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,
+ 16,17,18,19,20,21,22,23,-1,-1,-1,-1,-1,-1,-1,-1,
+ 24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
+ 32,33,34,35,36,37,38,39,-1,-1,-1,-1,-1,-1,-1,-1,
+ 40,41,42,43,44,45,46,47,-1,-1,-1,-1,-1,-1,-1,-1,
+ 48,49,50,51,52,53,54,55,-1,-1,-1,-1,-1,-1,-1,-1,
+ 56,57,58,59,60,61,62,63};
+short Dcode[120]=
+ {0,1,1,1,1,1,1,1,0,0,0,0,0,0,0x0E,0x0F,
+ 0x10,0x11,0x12,0,0,0,0,0,0,0,0,0,0,0,0x0F,0x1F,
+ 0x10,0x21,0x11,0,0,0,0,0,0,0,0,0,0,0x0F,0,0,
+ 0x10,0,0,0x11,0,0,0,0,0,0,0,0,0x0F,0,0,0,
+ 0x10,0,0,0,0x11,0,0,0,0,0,0,0x0F,0,0,0,0,
+ 0x10,0,0,0,0,0x11,0,0,0,0,0x0F,0,0,0,0,0,
+ 0x10,0,0,0,0,0,0x11,0,0,0x0F,0,0,0,0,0,0,
+ 0x10,0,0,0,0,0,0,0x11};
+short Stboard[64]=
+ {rook,knight,bishop,queen,king,bishop,knight,rook,
+ pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
+ 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,
+ pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
+ rook,knight,bishop,queen,king,bishop,knight,rook};
+short Stcolor[64]=
+ {white,white,white,white,white,white,white,white,
+ white,white,white,white,white,white,white,white,
+ 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,
+ black,black,black,black,black,black,black,black,
+ black,black,black,black,black,black,black,black};
+short sweep[7]= {false,false,false,true,true,true,false};
+short Dpwn[3]={4,6,0};
+short Dstart[7]={6,4,8,4,0,0,0};
+short Dstop[7]={7,5,15,7,3,7,7};
+short Dir[16]={1,0x10,-1,-0x10,0x0F,0x11,-0x0F,-0x11,
+ 0x0E,-0x0E,0x12,-0x12,0x1F,-0x1F,0x21,-0x21};
+short Pdir[34]={0,0x38,0,0,0,0,0,0,0,0,0,0,0,0,0x02,0x35,
+ 0x38,0x35,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0x02,
+ 0,0x02};
+short pbit[7]={0,0x01,0x02,0x04,0x08,0x10,0x20};
+unsigned short killr0[maxdepth],killr1[maxdepth],killr2[maxdepth];
+unsigned short killr3[maxdepth],PrVar[maxdepth];
+unsigned short PV,hint,Swag0,Swag1,Swag2,Swag3,Swag4;
+unsigned short hashkey;
+unsigned long hashbd;
+struct hashval hashcode[2][7][64];
+struct hashentry huge *ttable,*ptbl;
+unsigned char history[8192];
+
+short Mwpawn[64],Mbpawn[64],Mknight[2][64],Mbishop[2][64];
+short Mking[2][64],Kfield[2][64];
+short value[7]={0,valueP,valueN,valueB,valueR,valueQ,valueK};
+short control[7]={0,ctlP,ctlN,ctlB,ctlR,ctlQ,ctlK};
+short PassedPawn0[8]={0,60,80,120,200,360,600,800};
+short PassedPawn1[8]={0,30,40,60,100,180,300,800};
+short PassedPawn2[8]={0,15,25,35,50,90,140,800};
+short PassedPawn3[8]={0,5,10,15,20,30,140,800};
+short ISOLANI[8] = {-12,-16,-20,-24,-24,-20,-16,-12};
+short BACKWARD[8] = {-6,-10,-15,-21,-28,-28,-28,-28};
+short BMBLTY[14] = {-2,0,2,4,6,8,10,12,13,14,15,16,16,16};
+short RMBLTY[14] = {0,2,4,6,8,10,11,12,13,14,14,14,14,14};
+short Kthreat[16] = {0,-8,-20,-36,-52,-68,-80,-80,-80,-80,-80,-80,
+ -80,-80,-80,-80};
+short KNIGHTPOST,KNIGHTSTRONG,BISHOPSTRONG,KATAK,KBNKsq;
+short PEDRNK2B,PWEAKH,PADVNCM,PADVNCI,PAWNSHIELD,PDOUBLED,PBLOK;
+short RHOPN,RHOPNX,KHOPN,KHOPNX,KSFTY;
+short ATAKD,HUNGP,HUNGX,KCASTLD,KMOVD,XRAY,PINVAL;
+short stage,stage2,Zwmtl,Zbmtl,Developed[2],PawnStorm;
+short PawnBonus,BishopBonus,RookBonus;
+short KingOpening[64]=
+ { 0, 0, -4,-10,-10, -4, 0, 0,
+ -4, -4, -8,-12,-12, -8, -4, -4,
+ -12,-16,-20,-20,-20,-20,-16,-12,
+ -16,-20,-24,-24,-24,-24,-20,-16,
+ -16,-20,-24,-24,-24,-24,-20,-16,
+ -12,-16,-20,-20,-20,-20,-16,-12,
+ -4, -4, -8,-12,-12, -8, -4, -4,
+ 0, 0, -4,-10,-10, -4, 0, 0};
+short KingEnding[64]=
+ { 0, 4, 8,12,12, 8, 4, 0,
+ 4,16,20,24,24,20,16, 4,
+ 8,20,28,32,32,28,20, 8,
+ 12,24,32,36,36,32,24,12,
+ 12,24,32,36,36,32,24,12,
+ 8,20,28,32,32,28,20, 8,
+ 4,16,20,24,24,20,16, 4,
+ 0, 4, 8,12,12, 8, 4, 0};
+short KBNK[64]=
+ {99,90,80,70,60,50,40,40,
+ 90,80,60,50,40,30,20,40,
+ 80,60,40,30,20,10,30,50,
+ 70,50,30,10, 0,20,40,60,
+ 60,40,20, 0,10,30,50,70,
+ 50,30,10,20,30,40,60,80,
+ 40,20,30,40,50,60,80,90,
+ 40,40,50,60,70,80,90,99};
+short pknight[64]=
+ { 0, 4, 8,10,10, 8, 4, 0,
+ 4, 8,16,20,20,16, 8, 4,
+ 8,16,24,28,28,24,16, 8,
+ 10,20,28,32,32,28,20,10,
+ 10,20,28,32,32,28,20,10,
+ 8,16,24,28,28,24,16, 8,
+ 4, 8,16,20,20,16, 8, 4,
+ 0, 4, 8,10,10, 8, 4, 0};
+short pbishop[64]=
+ {14,14,14,14,14,14,14,14,
+ 14,22,18,18,18,18,22,14,
+ 14,18,22,22,22,22,18,14,
+ 14,18,22,22,22,22,18,14,
+ 14,18,22,22,22,22,18,14,
+ 14,18,22,22,22,22,18,14,
+ 14,22,18,18,18,18,22,14,
+ 14,14,14,14,14,14,14,14};
+short PawnAdvance[64]=
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 4, 0, 0, 4, 4, 4,
+ 6, 8, 2,10,10, 2, 8, 6,
+ 6, 8,12,16,16,12, 8, 6,
+ 8,12,16,24,24,16,12, 8,
+ 12,16,24,32,32,24,16,12,
+ 12,16,24,32,32,24,16,12,
+ 0, 0, 0, 0, 0, 0, 0, 0};
+
+/* ............ prototypes ............ */
+void ScorePosition( short side, short *score );
+void ScoreLoneKing( short side, short *score );
+int ScoreKPK( short side, short winner, short loser,
+ short king1, short king2, short sq );
+int ScoreKBNK( short winner, short king1, short king2 );
+int SqValue( short sq, short side );
+void KingScan( short sq, short *s );
+void BRscan( short sq, short *s, short *mob );
+int trapped( short sq, short piece );
+void ExaminePosition( void );
+void UpdateWeights( void );
+int distance( short a, short b );
+void BlendBoard( short a[64] , short b[64] , short c[64] );
+void CopyBoard( short a[64] , short b[64] );
+
+void OpeningBook ( void );
+int search ( short side, short ply, short depth,
+ short alpha, short beta,
+ unsigned short bstline[], short *rpt );
+int evaluate ( short side, short xside, short ply, short depth,
+ short alpha, short beta );
+int ProbeTTable ( short side, short depth,
+ short *alpha, short *beta, short *score);
+void PutInTTable ( short side, short score, short depth,
+ short alpha, short beta, unsigned short mv );
+void ZeroTTable ( void );
+void MoveList ( short side, short ply );
+
+void GenMoves ( short ply, short sq, short side, short xside );
+void LinkMove ( short ply, short f, short t, short xside );
+void CaptureList ( short side, short xside, short ply );
+int castle ( short side, short kf, short kt, short iop );
+void EnPassant ( short xside, short f, short t, short iop );
+void MakeMove ( short side, struct leaf *node,
+ short *tempb, short *tempc, short *tempsf, short *tempst );
+void UnmakeMove ( short side, struct leaf *node,
+ short *tempb, short *tempc, short *tempsf, short *tempst );
+void UpdateHashbd ( short side, short piece, short f, short t );
+void UpdatePieceList ( short side, short sq, short iop );
+void InitializeStats ( void );
+void pick ( short p1, short p2 );
+void repetition ( short *cnt );
+int SqAtakd ( short sq, short side );
+void ataks ( short side, short *a );
+
+void algbr ( short f, short t, short flag );
+void ElapsedTime( short iop);
+
+void NewGame(void);
+
+
+/* ............ POSITIONAL EVALUATION ROUTINES ............ */
+
+
+void ScorePosition(side,score)
+short side,*score;
+
+/*
+ Perform normal static evaluation of board position. A score is
+ generated for each piece and these are summed to get a score for each
+ side.
+*/
+
+{
+register short sq,s,i,xside;
+short pscore[3];
+
+ wking = PieceList[white][0]; bking = PieceList[black][0];
+ UpdateWeights();
+ xside = otherside[side];
+ pscore[white] = pscore[black] = 0;
+
+ /* ok, I will yield here although this function will be called much more
+ many times than needed I think */
+ rb->yield();
+
+ for (c1 = white; c1 <= black; c1++)
+ {
+ c2 = otherside[c1];
+ if (c1 == white) EnemyKing = bking; else EnemyKing = wking;
+ atk1 = atak[c1]; atk2 = atak[c2];
+ PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
+ for (i = 0; i <= PieceCnt[c1]; i++)
+ {
+ sq = PieceList[c1][i];
+ s = SqValue(sq,side);
+ pscore[c1] += s;
+ svalue[sq] = s;
+ }
+ }
+ if (hung[side] > 1) pscore[side] += HUNGX;
+ if (hung[xside] > 1) pscore[xside] += HUNGX;
+
+ *score = mtl[side] - mtl[xside] + pscore[side] - pscore[xside] + 10;
+ if (dither) *score += rb->rand() % dither;
+
+ if (*score > 0 && pmtl[side] == 0) {
+ if (emtl[side] < valueR) {
+ *score = 0;
+ } else {
+ if (*score < valueR) *score /= 2;
+ }
+ }
+ if (*score < 0 && pmtl[xside] == 0) {
+ if (emtl[xside] < valueR) {
+ *score = 0;
+ } else {
+ if (-*score < valueR) *score /= 2;
+ }
+ }
+
+ if (mtl[xside] == valueK && emtl[side] > valueB) *score += 200;
+ if (mtl[side] == valueK && emtl[xside] > valueB) *score -= 200;
+}
+
+
+void ScoreLoneKing(side,score)
+short side,*score;
+
+/*
+ Static evaluation when loser has only a king and winner has no pawns
+ or no pieces.
+*/
+
+{
+register short winner,loser,king1,king2,s,i;
+
+ UpdateWeights();
+ if (mtl[white] > mtl[black]) winner = white; else winner = black;
+ loser = otherside[winner];
+ king1 = PieceList[winner][0]; king2 = PieceList[loser][0];
+
+ s = 0;
+
+ if (pmtl[winner] > 0)
+ for (i = 1; i <= PieceCnt[winner]; i++)
+ s += ScoreKPK(side,winner,loser,king1,king2,PieceList[winner][i]);
+
+ else if (emtl[winner] == valueB+valueN)
+ s = ScoreKBNK(winner,king1,king2);
+
+ else if (emtl[winner] > valueB)
+ s = 500 + emtl[winner] - 2*KingEnding[king2] - 2*distance(king1,king2);
+
+ if (side == winner) *score = s; else *score = -s;
+}
+
+
+int ScoreKPK(side,winner,loser,king1,king2,sq)
+short side,winner,loser,king1,king2,sq;
+
+/*
+ Score King and Pawns versus King endings.
+*/
+
+{
+register short s,r;
+
+ if (PieceCnt[winner] == 1) s = 50; else s = 120;
+ if (winner == white)
+ {
+ if (side == loser) r = row[sq]-1; else r = row[sq];
+ if (row[king2] >= r && distance(sq,king2) < 8-r) s += 10*row[sq];
+ else s = 500+50*row[sq];
+ if (row[sq] < 6) sq += 16; else sq += 8;
+ }
+ else
+ {
+ if (side == loser) r = row[sq]+1; else r = row[sq];
+ if (row[king2] <= r && distance(sq,king2) < r+1) s += 10*(7-row[sq]);
+ else s = 500+50*(7-row[sq]);
+ if (row[sq] > 1) sq -= 16; else sq -= 8;
+ }
+ s += 8*(taxicab(king2,sq) - taxicab(king1,sq));
+ return(s);
+}
+
+
+int ScoreKBNK(winner,king1,king2)
+short winner,king1,king2;
+
+/*
+ Score King+Bishop+Knight versus King endings.
+ This doesn't work all that well but it's better than nothing.
+*/
+
+{
+register short s;
+ s = emtl[winner] - 300;
+ if (KBNKsq == 0) s += KBNK[king2];
+ else s += KBNK[locn[row[king2]][7-column[king2]]];
+ s -= taxicab(king1,king2);
+ s -= distance(PieceList[winner][1],king2);
+ s -= distance(PieceList[winner][2],king2);
+ return(s);
+}
+
+
+int SqValue(sq,side)
+short sq,side;
+
+/*
+ Calculate the positional value for the piece on 'sq'.
+*/
+
+{
+register short j,fyle,rank,a1,a2;
+short s,piece,in_square,r,mob,e,c;
+
+ piece = board[sq];
+ a1 = (atk1[sq] & 0x4FFF); a2 = (atk2[sq] & 0x4FFF);
+ rank = row[sq]; fyle = column[sq];
+ s = 0;
+ if (piece == pawn && c1 == white)
+ {
+ s = Mwpawn[sq];
+ if (sq == 11 || sq == 12)
+ if (color[sq+8] != neutral) s += PEDRNK2B;
+ if ((fyle == 0 || PC1[fyle-1] == 0) &&
+ (fyle == 7 || PC1[fyle+1] == 0))
+ s += ISOLANI[fyle];
+ else if (PC1[fyle] > 1) s += PDOUBLED;
+ if (a1 < ctlP && atk1[sq+8] < ctlP)
+ {
+ s += BACKWARD[a2 & 0xFF];
+ if (PC2[fyle] == 0) s += PWEAKH;
+ if (color[sq+8] != neutral) s += PBLOK;
+ }
+ if (PC2[fyle] == 0)
+ {
+ if (side == black) r = rank-1; else r = rank;
+ in_square = (row[bking] >= r && distance(sq,bking) < 8-r);
+ if (a2 == 0 || side == white) e = 0; else e = 1;
+ for (j = sq+8; j < 64; j += 8)
+ if (atk2[j] >= ctlP) { e = 2; break; }
+ else if (atk2[j] > 0 || color[j] != neutral) e = 1;
+ if (e == 2) s += (stage*PassedPawn3[rank]) / 10;
+ else if (in_square || e == 1) s += (stage*PassedPawn2[rank]) / 10;
+ else if (emtl[black] > 0) s += (stage*PassedPawn1[rank]) / 10;
+ else s += PassedPawn0[rank];
+ }
+ }
+ else if (piece == pawn && c1 == black)
+ {
+ s = Mbpawn[sq];
+ if (sq == 51 || sq == 52)
+ if (color[sq-8] != neutral) s += PEDRNK2B;
+ if ((fyle == 0 || PC1[fyle-1] == 0) &&
+ (fyle == 7 || PC1[fyle+1] == 0))
+ s += ISOLANI[fyle];
+ else if (PC1[fyle] > 1) s += PDOUBLED;
+ if (a1 < ctlP && atk1[sq-8] < ctlP)
+ {
+ s += BACKWARD[a2 & 0xFF];
+ if (PC2[fyle] == 0) s += PWEAKH;
+ if (color[sq-8] != neutral) s += PBLOK;
+ }
+ if (PC2[fyle] == 0)
+ {
+ if (side == white) r = rank+1; else r = rank;
+ in_square = (row[wking] <= r && distance(sq,wking) < r+1);
+ if (a2 == 0 || side == black) e = 0; else e = 1;
+ for (j = sq-8; j >= 0; j -= 8)
+ if (atk2[j] >= ctlP) { e = 2; break; }
+ else if (atk2[j] > 0 || color[j] != neutral) e = 1;
+ if (e == 2) s += (stage*PassedPawn3[7-rank]) / 10;
+ else if (in_square || e == 1) s += (stage*PassedPawn2[7-rank]) / 10;
+ else if (emtl[white] > 0) s += (stage*PassedPawn1[7-rank]) / 10;
+ else s += PassedPawn0[7-rank];
+ }
+ }
+ else if (piece == knight)
+ {
+ s = Mknight[c1][sq];
+ }
+ else if (piece == bishop)
+ {
+ s = Mbishop[c1][sq];
+ BRscan(sq,&s,&mob);
+ s += BMBLTY[mob];
+ }
+ else if (piece == rook)
+ {
+ s += RookBonus;
+ BRscan(sq,&s,&mob);
+ s += RMBLTY[mob];
+ if (PC1[fyle] == 0) s += RHOPN;
+ if (PC2[fyle] == 0) s += RHOPNX;
+ if (rank == rank7[c1] && pmtl[c2] > 100) s += 10;
+ if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
+ }
+ else if (piece == queen)
+ {
+ if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
+ if (distance(sq,EnemyKing) < 3) s += 12;
+ }
+ else if (piece == king)
+ {
+ s = Mking[c1][sq];
+ if (KSFTY > 0)
+ if (Developed[c2] || stage > 0) KingScan(sq,&s);
+ if (castld[c1]) s += KCASTLD;
+ else if (kingmoved[c1]) s += KMOVD;
+
+ if (PC1[fyle] == 0) s += KHOPN;
+ if (PC2[fyle] == 0) s += KHOPNX;
+ if (fyle == 1 || fyle == 2 || fyle == 3 || fyle == 7)
+ {
+ if (PC1[fyle-1] == 0) s += KHOPN;
+ if (PC2[fyle-1] == 0) s += KHOPNX;
+ }
+ if (fyle == 4 || fyle == 5 || fyle == 6 || fyle == 0)
+ {
+ if (PC1[fyle+1] == 0) s += KHOPN;
+ if (PC2[fyle+1] == 0) s += KHOPNX;
+ }
+ if (fyle == 2)
+ {
+ if (PC1[0] == 0) s += KHOPN;
+ if (PC2[0] == 0) s += KHOPNX;
+ }
+ if (fyle == 5)
+ {
+ if (PC1[7] == 0) s += KHOPN;
+ if (PC2[7] == 0) s += KHOPNX;
+ }
+ }
+
+ if (a2 > 0)
+ {
+ c = (control[piece] & 0x4FFF);
+ if (a1 == 0 || a2 > c+1)
+ {
+ s += HUNGP;
+ ++hung[c1];
+ if (piece != king && trapped(sq,piece)) ++hung[c1];
+ }
+ else if (piece != pawn || a2 > a1)
+ if (a2 >= c || a1 < ctlP) s += ATAKD;
+ }
+ return(s);
+}
+
+
+void KingScan(sq,s)
+short sq,*s;
+
+/*
+ Assign penalties if king can be threatened by checks, if squares
+ near the king are controlled by the enemy (especially the queen),
+ or if there are no pawns near the king.
+*/
+
+#define ScoreThreat\
+ if (color[u] != c2) {\
+ if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) {\
+ ++cnt;\
+ } else {\
+ *s -= 3; \
+ }\
+ }
+
+{
+register short m,u,d,i,m0,cnt,ok;
+
+ cnt = 0;
+ m0 = map[sq];
+ if (HasBishop[c2] || HasQueen[c2])
+ for (i = Dstart[bishop]; i <= Dstop[bishop]; i++)
+ {
+ d = Dir[i]; m = m0+d;
+ while (!(m & 0x88))
+ {
+ u = unmap[m];
+ if (atk2[u] & ctlBQ) ScoreThreat
+ if (color[u] != neutral) break;
+ m += d;
+ }
+ }
+ if (HasRook[c2] || HasQueen[c2])
+ for (i = Dstart[rook]; i <= Dstop[rook]; i++)
+ {
+ d = Dir[i]; m = m0+d;
+ while (!(m & 0x88))
+ {
+ u = unmap[m];
+ if (atk2[u] & ctlRQ) ScoreThreat
+ if (color[u] != neutral) break;
+ m += d;
+ }
+ }
+ if (HasKnight[c2])
+ for (i = Dstart[knight]; i <= Dstop[knight]; i++)
+ if (!((m = m0+Dir[i]) & 0x88))
+ {
+ u = unmap[m];
+ if (atk2[u] & ctlNN) ScoreThreat
+ }
+ *s += (KSFTY*Kthreat[cnt]) / 16;
+
+ cnt = 0; ok = false;
+ m0 = map[sq];
+ for (i = Dstart[king]; i <= Dstop[king]; i++)
+ if (!((m = m0+Dir[i]) & 0x88))
+ {
+ u = unmap[m];
+ if (board[u] == pawn) ok = true;
+ if (atk2[u] > atk1[u])
+ {
+ ++cnt;
+ if (atk2[u] & ctlQ)
+ if (atk2[u] > ctlQ+1 && atk1[u] < ctlQ) *s -= 4*KSFTY;
+ }
+ }
+ if (!ok) *s -= KSFTY;
+ if (cnt > 1) *s -= KSFTY;
+}
+
+
+void BRscan(sq,s,mob)
+short sq,*s,*mob;
+
+/*
+ Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
+ hung[] array if a pin is found.
+*/
+
+{
+register short m,u,d,m0,j,piece,pin;
+short *Kf;
+
+ Kf = Kfield[c1];
+ *mob = 0;
+ m0 = map[sq]; piece = board[sq];
+ for (j = Dstart[piece]; j <= Dstop[piece]; j++)
+ {
+ pin = -1;
+ d = Dir[j]; m = m0+d;
+ while (!(m & 0x88))
+ {
+ u = unmap[m]; *s += Kf[u];
+ if (color[u] == neutral)
+ {
+ (*mob)++;
+ m += d;
+ }
+ else if (pin < 0)
+ {
+ if (board[u] == pawn || board[u] == king) break;
+ pin = u;
+ m += d;
+ }
+ else if (color[u] == c2 && (board[u] > piece || atk2[u] == 0))
+ {
+ if (color[pin] == c2)
+ {
+ *s += PINVAL;
+ if (atk2[pin] == 0 ||
+ atk1[pin] > control[board[pin]]+1)
+ ++hung[c2];
+ }
+ else *s += XRAY;
+ break;
+ }
+ else break;
+ }
+ }
+}
+
+
+int trapped(sq,piece)
+short sq,piece;
+
+/*
+ See if the attacked piece has unattacked squares to move to.
+*/
+
+{
+register short u,m,d,i,m0;
+
+ m0 = map[sq];
+ if (sweep[piece])
+ for (i = Dstart[piece]; i <= Dstop[piece]; i++)
+ {
+ d = Dir[i]; m = m0+d;
+ while (!(m & 0x88))
+ {
+ u = unmap[m];
+ if (color[u] == c1) break;
+ if (atk2[u] == 0 || board[u] >= piece) return(false);
+ if (color[u] == c2) break;
+ m += d;
+ }
+ }
+ else if (piece == pawn)
+ {
+ if (c1 == white) u = sq+8; else u = sq-8;
+ if (color[u] == neutral && atk1[u] >= atk2[u])
+ return(false);
+ if (!((m = m0+Dir[Dpwn[c1]]) & 0x88))
+ if (color[unmap[m]] == c2) return(false);
+ if (!((m = m0+Dir[Dpwn[c1]+1]) & 0x88))
+ if (color[unmap[m]] == c2) return(false);
+ }
+ else
+ {
+ for (i = Dstart[piece]; i <= Dstop[piece]; i++)
+ if (!((m = m0+Dir[i]) & 0x88))
+ {
+ u = unmap[m];
+ if (color[u] != c1)
+ if (atk2[u] == 0 || board[u] >= piece) return(false);
+ }
+ }
+ return(true);
+}
+
+
+void ExaminePosition()
+
+/*
+ This is done one time before the search is started. Set up arrays
+ Mwpawn, Mbpawn, Mknight, Mbishop, Mking which are used in the
+ SqValue() function to determine the positional value of each piece.
+*/
+
+{
+register short i,sq;
+short wpadv,bpadv,wstrong,bstrong,z,side,pp,j,val,Pd,fyle,rank;
+
+ wking = PieceList[white][0]; bking = PieceList[black][0];
+ ataks(white,atak[white]); ataks(black,atak[black]);
+ Zwmtl = Zbmtl = 0;
+ UpdateWeights();
+ HasPawn[white] = HasPawn[black] = 0;
+ HasKnight[white] = HasKnight[black] = 0;
+ HasBishop[white] = HasBishop[black] = 0;
+ HasRook[white] = HasRook[black] = 0;
+ HasQueen[white] = HasQueen[black] = 0;
+ for (side = white; side <= black; side++)
+ for (i = 0; i <= PieceCnt[side]; i++)
+ switch (board[PieceList[side][i]])
+ {
+ case pawn : ++HasPawn[side]; break;
+ case knight : ++HasKnight[side]; break;
+ case bishop : ++HasBishop[side]; break;
+ case rook : ++HasRook[side]; break;
+ case queen : ++HasQueen[side]; break;
+ }
+ if (!Developed[white])
+ Developed[white] = (board[1] != knight && board[2] != bishop &&
+ board[5] != bishop && board[6] != knight);
+ if (!Developed[black])
+ Developed[black] = (board[57] != knight && board[58] != bishop &&
+ board[61] != bishop && board[62] != knight);
+ if (!PawnStorm && stage < 5)
+ PawnStorm = ((column[wking] < 3 && column[bking] > 4) ||
+ (column[wking] > 4 && column[bking] < 3));
+
+ CopyBoard(pknight,Mknight[white]);
+ CopyBoard(pknight,Mknight[black]);
+ CopyBoard(pbishop,Mbishop[white]);
+ CopyBoard(pbishop,Mbishop[black]);
+ BlendBoard(KingOpening,KingEnding,Mking[white]);
+ BlendBoard(KingOpening,KingEnding,Mking[black]);
+
+ for (sq = 0; sq < 64; sq++)
+ {
+ fyle = column[sq]; rank = row[sq];
+ wstrong = bstrong = true;
+ for (i = sq; i < 64; i += 8)
+ if (atak[black][i] >= ctlP) wstrong = false;
+ for (i = sq; i >= 0; i -= 8)
+ if (atak[white][i] >= ctlP) bstrong = false;
+ wpadv = bpadv = PADVNCM;
+ if ((fyle == 0 || PawnCnt[white][fyle-1] == 0) &&
+ (fyle == 7 || PawnCnt[white][fyle+1] == 0)) wpadv = PADVNCI;
+ if ((fyle == 0 || PawnCnt[black][fyle-1] == 0) &&
+ (fyle == 7 || PawnCnt[black][fyle+1] == 0)) bpadv = PADVNCI;
+ Mwpawn[sq] = (wpadv*PawnAdvance[sq]) / 10;
+ Mbpawn[sq] = (bpadv*PawnAdvance[63-sq]) / 10;
+ Mwpawn[sq] += PawnBonus; Mbpawn[sq] += PawnBonus;
+ if (castld[white] || kingmoved[white])
+ {
+ if ((fyle < 3 || fyle > 4) && distance(sq,wking) < 3)
+ Mwpawn[sq] += PAWNSHIELD;
+ }
+ else if (rank < 3 && (fyle < 2 || fyle > 5))
+ Mwpawn[sq] += PAWNSHIELD / 2;
+ if (castld[black] || kingmoved[black])
+ {
+ if ((fyle < 3 || fyle > 4) && distance(sq,bking) < 3)
+ Mbpawn[sq] += PAWNSHIELD;
+ }
+ else if (rank > 4 && (fyle < 2 || fyle > 5))
+ Mbpawn[sq] += PAWNSHIELD / 2;
+ if (PawnStorm)
+ {
+ if ((column[wking] < 4 && fyle > 4) ||
+ (column[wking] > 3 && fyle < 3)) Mwpawn[sq] += 3*rank - 21;
+ if ((column[bking] < 4 && fyle > 4) ||
+ (column[bking] > 3 && fyle < 3)) Mbpawn[sq] -= 3*rank;
+ }
+
+ Mknight[white][sq] += 5 - distance(sq,bking);
+ Mknight[white][sq] += 5 - distance(sq,wking);
+ Mknight[black][sq] += 5 - distance(sq,wking);
+ Mknight[black][sq] += 5 - distance(sq,bking);
+ Mbishop[white][sq] += BishopBonus;
+ Mbishop[black][sq] += BishopBonus;
+ for (i = 0; i <= PieceCnt[black]; i++)
+ if (distance(sq,PieceList[black][i]) < 3)
+ Mknight[white][sq] += KNIGHTPOST;
+ for (i = 0; i <= PieceCnt[white]; i++)
+ if (distance(sq,PieceList[white][i]) < 3)
+ Mknight[black][sq] += KNIGHTPOST;
+ if (wstrong) Mknight[white][sq] += KNIGHTSTRONG;
+ if (bstrong) Mknight[black][sq] += KNIGHTSTRONG;
+ if (wstrong) Mbishop[white][sq] += BISHOPSTRONG;
+ if (bstrong) Mbishop[black][sq] += BISHOPSTRONG;
+
+ if (HasBishop[white] == 2) Mbishop[white][sq] += 8;
+ if (HasBishop[black] == 2) Mbishop[black][sq] += 8;
+ if (HasKnight[white] == 2) Mknight[white][sq] += 5;
+ if (HasKnight[black] == 2) Mknight[black][sq] += 5;
+
+ if (board[sq] == bishop) {
+ if (rank % 2 == fyle % 2) {
+ KBNKsq = 0;
+ } else {
+ KBNKsq = 7;
+ }
+ }
+
+ Kfield[white][sq] = Kfield[black][sq] = 0;
+ if (distance(sq,wking) == 1) Kfield[black][sq] = KATAK;
+ if (distance(sq,bking) == 1) Kfield[white][sq] = KATAK;
+
+ Pd = 0;
+ for (i = 0; i < 64; i++)
+ if (board[i] == pawn)
+ {
+ if (color[i] == white)
+ {
+ pp = true;
+ if (row[i] == 6) z = i+8; else z = i+16;
+ for (j = i+8; j < 64; j += 8)
+ if (atak[black][j] > ctlP || board[j] == pawn) pp = false;
+ }
+ else
+ {
+ pp = true;
+ if (row[i] == 1) z = i-8; else z = i-16;
+ for (j = i-8; j >= 0; j -= 8)
+ if (atak[white][j] > ctlP || board[j] == pawn) pp = false;
+ }
+ if (pp) Pd += 5*taxicab(sq,z); else Pd += taxicab(sq,z);
+ }
+ if (Pd != 0)
+ {
+ val = (Pd*stage2) / 10;
+ Mking[white][sq] -= val;
+ Mking[black][sq] -= val;
+ }
+ }
+}
+
+
+void UpdateWeights()
+
+/*
+ If material balance has changed, determine the values for the
+ positional evaluation terms.
+*/
+
+{
+register short tmtl;
+
+ if (mtl[white] != Zwmtl || mtl[black] != Zbmtl)
+ {
+ Zwmtl = mtl[white]; Zbmtl = mtl[black];
+ emtl[white] = Zwmtl - pmtl[white] - valueK;
+ emtl[black] = Zbmtl - pmtl[black] - valueK;
+ tmtl = emtl[white] + emtl[black];
+ if (tmtl > 6600) stage = 0;
+ else if (tmtl < 1400) stage = 10;
+ else stage = (6600-tmtl) / 520;
+ if (tmtl > 3600) stage2 = 0;
+ else if (tmtl < 1400) stage2 = 10;
+ else stage2 = (3600-tmtl) / 220;
+
+ PEDRNK2B = -15; /* centre pawn on 2nd rank & blocked */
+ PBLOK = -4; /* blocked backward pawn */
+ PDOUBLED = -14; /* doubled pawn */
+ PWEAKH = -4; /* weak pawn on half open file */
+ PAWNSHIELD = 10-stage; /* pawn near friendly king */
+ PADVNCM = 10; /* advanced pawn multiplier */
+ PADVNCI = 7; /* muliplier for isolated pawn */
+ PawnBonus = stage;
+
+ KNIGHTPOST = (stage+2)/3; /* knight near enemy pieces */
+ KNIGHTSTRONG = (stage+6)/2; /* occupies pawn hole */
+
+ BISHOPSTRONG = (stage+6)/2; /* occupies pawn hole */
+ BishopBonus = 2*stage;
+
+ RHOPN = 10; /* rook on half open file */
+ RHOPNX = 4;
+ RookBonus = 6*stage;
+
+ XRAY = 8; /* Xray attack on piece */
+ PINVAL = 10; /* Pin */
+
+ KHOPN = (3*stage-30) / 2; /* king on half open file */
+ KHOPNX = KHOPN / 2;
+ KCASTLD = 10 - stage;
+ KMOVD = -40 / (stage+1); /* king moved before castling */
+ KATAK = (10-stage) / 2; /* B,R attacks near enemy king */
+ if (stage < 8) KSFTY = 16-2*stage; else KSFTY = 0;
+
+ ATAKD = -6; /* defender > attacker */
+ HUNGP = -8; /* each hung piece */
+ HUNGX = -12; /* extra for >1 hung piece */
+ }
+}
+
+
+int distance(a,b)
+short a,b;
+{
+register short d1,d2;
+
+ d1 = abs(column[a]-column[b]);
+ d2 = abs(row[a]-row[b]);
+ if (d1 > d2) return(d1); else return(d2);
+}
+
+
+void BlendBoard(a,b,c)
+short a[64],b[64],c[64];
+{
+register int sq;
+ for (sq = 0; sq < 64; sq++)
+ c[sq] = (a[sq]*(10-stage) + b[sq]*stage) / 10;
+}
+
+
+void CopyBoard(a,b)
+short a[64],b[64];
+{
+register int sq;
+ for (sq = 0; sq < 64; sq++)
+ b[sq] = a[sq];
+}
+
+/* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
+
+
+int SelectMove(side,iop)
+short side,iop;
+
+/*
+ Select a move by calling function search() at progressively deeper
+ ply until time is up or a mate or draw is reached. An alpha-beta
+ window of -90 to +90 points is set around the score returned from the
+ previous iteration. If Sdepth != 0 then the program has correctly
+ predicted the opponents move and the search will start at a depth of
+ Sdepth+1 rather than a depth of 1.
+*/
+
+{
+static short i,alpha,beta,score,tempb,tempc,tempsf,tempst,xside,rpt;
+
+ timeout = false;
+ xside = otherside[side];
+ if (iop != 2) player = side;
+ if (TCflag)
+ {
+ ResponseTime = (TimeControl.clock[side]) /
+ (TimeControl.moves[side] + 3) -
+ OperatorTime;
+ ResponseTime += (ResponseTime*TimeControl.moves[side])/(2*TCmoves+1);
+ }
+ else ResponseTime = Level;
+ if (iop == 2) ResponseTime = 999;
+ if (Sdepth > 0 && root->score > Zscore-zwndw) ResponseTime -= ft;
+ else if (ResponseTime < 1) ResponseTime = 1;
+ ExtraTime = 0;
+ ExaminePosition();
+ ScorePosition(side,&score);
+ Pscore[0] = -score;
+
+ if (Sdepth == 0)
+ {
+ ZeroTTable();
+ /*SearchStartStuff(side);*/
+ for (i = 0; i < 8192; i++) history[i] = 0;
+ FROMsquare = TOsquare = -1;
+ PV = 0;
+ if (iop != 2) hint = 0;
+ for (i = 0; i < maxdepth; i++)
+ PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
+
+ alpha = -9000; beta = 9000;
+ rpt = 0;
+ TrPnt[1] = 0; root = &Tree[0];
+ MoveList(side,1);
+ for (i = TrPnt[1]; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
+ /*if (Book != NULL) OpeningBook();*/
+ if (Book != NULL) timeout = true;
+ NodeCnt = ETnodes = EvalNodes = HashCnt = 0;
+ Zscore = 0; zwndw = 20;
+ }
+
+ while (!timeout && Sdepth < MaxSearchDepth)
+ {
+ Sdepth++;
+ /*ShowDepth(' ');*/
+ score = search(side,1,Sdepth,alpha,beta,PrVar,&rpt);
+ for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
+ if (score < alpha && !timeout)
+ {
+ /*ShowDepth('-');*/
+ ExtraTime = 10*ResponseTime;
+ ZeroTTable();
+ score = search(side,1,Sdepth,-9000,beta,PrVar,&rpt);
+ }
+ if (score > beta && !timeout && !(root->flags & exact))
+ {
+ /*ShowDepth('+');*/
+ ExtraTime = 0;
+ ZeroTTable();
+ score = search(side,1,Sdepth,alpha,9000,PrVar,&rpt);
+ }
+ score = root->score;
+ if (!timeout)
+ for (i = TrPnt[1]+1; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
+ /*ShowResults(score,PrVar,'.');*/
+ for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
+ if (score > Zscore-zwndw && score > Tree[1].score+250) ExtraTime = 0;
+ else if (score > Zscore-3*zwndw) ExtraTime = ResponseTime;
+ else ExtraTime = 3*ResponseTime;
+ if (root->flags & exact) timeout = true;
+ if (Tree[1].score < -9000) timeout = true;
+ if (4*et > 2*ResponseTime + ExtraTime) timeout = true;
+ if (!timeout)
+ {
+ Tscore[0] = score;
+ if (Zscore == 0) Zscore = score;
+ else Zscore = (Zscore+score)/2;
+ }
+ zwndw = 20+abs(Zscore/12);
+ beta = score + Bwindow;
+ if (Zscore < score) alpha = Zscore - Awindow - zwndw;
+ else alpha = score - Awindow - zwndw;
+ }
+
+ score = root->score;
+ if (rpt >= 2 || score < -12000) root->flags |= draw;
+ if (iop == 2) return(0);
+ if (Book == NULL) hint = PrVar[2];
+ ElapsedTime(1);
+
+ if (score > -9999 && rpt <= 2)
+ {
+ MakeMove(side,root,&tempb,&tempc,&tempsf,&tempst);
+ algbr(root->f,root->t,root->flags & cstlmask);
+ }
+ else mvstr1[0] = '\0';
+ /*OutputMove();*/
+ if (score == -9999 || score == 9998) mate = true;
+ if (mate) hint = 0;
+ if (root->flags & cstlmask) Game50 = GameCnt;
+ else if (board[root->t] == pawn || (root->flags & capture))
+ Game50 = GameCnt;
+ GameList[GameCnt].score = score;
+ GameList[GameCnt].nodes = NodeCnt;
+ GameList[GameCnt].time = (short)et;
+ GameList[GameCnt].depth = Sdepth;
+ if (TCflag)
+ {
+ TimeControl.clock[side] -= (et + OperatorTime);
+ if (--TimeControl.moves[side] == 0) SetTimeControl();
+ }
+ if ((root->flags & draw) && bothsides) quit = true;
+ if (GameCnt > 238) quit = true;
+ player = xside;
+ Sdepth = 0;
+ return(0);
+}
+
+
+void OpeningBook()
+
+/*
+ Go thru each of the opening lines of play and check for a match with
+ the current game listing. If a match occurs, generate a random number.
+ If this number is the largest generated so far then the next move in
+ this line becomes the current "candidate". After all lines are
+ checked, the candidate move is put at the top of the Tree[] array and
+ will be played by the program. Note that the program does not handle
+ book transpositions.
+*/
+
+{
+short j,pnt;
+unsigned short m,*mp;
+unsigned r,r0;
+struct BookEntry *p;
+
+ rb->srand((unsigned)time0);
+ r0 = m = 0;
+ p = Book;
+ while (p != NULL)
+ {
+ mp = p->mv;
+ for (j = 0; j <= GameCnt; j++)
+ if (GameList[j].gmove != *(mp++)) break;
+ if (j > GameCnt)
+ if ((r=rb->rand()) > r0)
+ {
+ r0 = r; m = *mp;
+ hint = *(++mp);
+ }
+ p = p->next;
+ }
+
+ for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
+ if ((Tree[pnt].f<<8) + Tree[pnt].t == m) Tree[pnt].score = 0;
+ pick(TrPnt[1],TrPnt[2]-1);
+ if (Tree[TrPnt[1]].score < 0) Book = NULL;
+}
+
+
+ /*if (post) ShowCurrentMove(pnt,node->f,node->t);\*/
+#define UpdateSearchStatus \
+{\
+ if (pnt > TrPnt[1])\
+ {\
+ d = best-Zscore; e = best-node->score;\
+ if (best < alpha) ExtraTime = 10*ResponseTime;\
+ else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\
+ else if (d > -zwndw) ExtraTime = 0;\
+ else if (d > -3*zwndw) ExtraTime = ResponseTime;\
+ else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\
+ else ExtraTime = 5*ResponseTime;\
+ }\
+}
+
+int search(side,ply,depth,alpha,beta,bstline,rpt)
+short side,ply,depth,alpha,beta,*rpt;
+unsigned short bstline[];
+
+/*
+ Perform an alpha-beta search to determine the score for the current
+ board position. If depth <= 0 only capturing moves, pawn promotions
+ and responses to check are generated and searched, otherwise all
+ moves are processed. The search depth is modified for check evasions,
+ certain re-captures and threats. Extensions may continue for up to 11
+ ply beyond the nominal search depth.
+*/
+
+#define prune (cf && score+node->score < alpha)
+#define ReCapture (rcptr && score > alpha && score < beta &&\
+ ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2] &&\
+ depth == Sdepth-ply+1)
+#define Parry (hung[side] > 1 && ply == Sdepth+1)
+#define MateThreat (ply < Sdepth+4 && ply > 4 &&\
+ ChkFlag[ply-2] && ChkFlag[ply-4] &&\
+ ChkFlag[ply-2] != ChkFlag[ply-4])
+
+{
+register short j,pnt;
+short best,tempb,tempc,tempsf,tempst;
+short xside,pbst,d,e,cf,score,rcnt;
+unsigned short mv,nxtline[maxdepth];
+struct leaf *node,tmp;
+
+ NodeCnt++;
+ xside = otherside[side];
+
+ if (ply <= Sdepth+3) repetition(rpt); else *rpt = 0;
+ if (*rpt >= 2) return(0);
+
+ score = evaluate(side,xside,ply,depth,alpha,beta);
+ if (score > 9000) return(score);
+
+ if (depth > 0)
+ {
+ if (InChk || PawnThreat[ply-1] || ReCapture) ++depth;
+ }
+ else
+ {
+ if (score >= alpha &&
+ (InChk || PawnThreat[ply-1] || Parry)) depth = 1;
+ else if (score <= beta && MateThreat) depth = 1;
+ }
+
+ PV = 0;
+ if (depth > 0 && hashflag && ply > 1)
+ {
+ ProbeTTable(side,depth,&alpha,&beta,&score);
+ bstline[ply] = PV;
+ bstline[ply+1] = 0;
+ if (beta == -20000) return(score);
+ if (alpha > beta) return(alpha);
+ }
+
+ if (Sdepth == 1) d = 7; else d = 11;
+ if (ply > Sdepth+d || (depth <= 0 && score > beta)) return(score);
+
+ if (ply > 1) {
+ if (depth > 0) {
+ MoveList(side,ply);
+ } else {
+ CaptureList(side,xside,ply);
+ }
+ }
+
+ if (TrPnt[ply] == TrPnt[ply+1]) return(score);
+
+ cf = (depth < 1 && ply > Sdepth+1 && !ChkFlag[ply-2] && !slk);
+
+ if (depth > 0) best = -12000; else best = score;
+ if (best > alpha) alpha = best;
+
+ for (pnt = pbst = TrPnt[ply];
+ pnt < TrPnt[ply+1] && best <= beta;
+ pnt++)
+ {
+ if (ply > 1) pick(pnt,TrPnt[ply+1]-1);
+ node = &Tree[pnt];
+ mv = (node->f << 8) + node->t;
+ nxtline[ply+1] = 0;
+
+ if (prune) break;
+ if (ply == 1) UpdateSearchStatus;
+
+ if (!(node->flags & exact))
+ {
+ MakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
+ CptrFlag[ply] = (node->flags & capture);
+ PawnThreat[ply] = (node->flags & pwnthrt);
+ Tscore[ply] = node->score;
+ node->score = -search(xside,ply+1,depth-1,-beta,-alpha,
+ nxtline,&rcnt);
+ if (abs(node->score) > 9000) node->flags |= exact;
+ else if (rcnt == 1) node->score /= 2;
+ if (rcnt >= 2 || GameCnt-Game50 > 99 ||
+ (node->score == 9999-ply && !ChkFlag[ply]))
+ {
+ node->flags |= draw; node->flags |= exact;
+ if (side == computer) node->score = contempt;
+ else node->score = -contempt;
+ }
+ UnmakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
+ }
+ if (node->score > best && !timeout)
+ {
+ if (depth > 0)
+ if (node->score > alpha && !(node->flags & exact))
+ node->score += depth;
+ best = node->score; pbst = pnt;
+ if (best > alpha) alpha = best;
+ for (j = ply+1; nxtline[j] > 0; j++) bstline[j] = nxtline[j];
+ bstline[j] = 0;
+ bstline[ply] = mv;
+ if (ply == 1)
+ {
+ if (best == alpha)
+ {
+ tmp = Tree[pnt];
+ for (j = pnt-1; j >= 0; j--) Tree[j+1] = Tree[j];
+ Tree[0] = tmp;
+ pbst = 0;
+ }
+ /*if (Sdepth > 2)
+ if (best > beta) ShowResults(best,bstline,'+');
+ else if (best < alpha) ShowResults(best,bstline,'-');
+ else ShowResults(best,bstline,'&');*/
+ }
+ }
+ if (NodeCnt > ETnodes) ElapsedTime(0);
+ if (timeout) return(-Tscore[ply-1]);
+ }
+
+ node = &Tree[pbst];
+ mv = (node->f<<8) + node->t;
+ if (hashflag && ply <= Sdepth && *rpt == 0 && best == alpha)
+ PutInTTable(side,best,depth,alpha,beta,mv);
+ if (depth > 0)
+ {
+ j = (node->f<<6) + node->t; if (side == black) j |= 0x1000;
+ if (history[j] < 150) history[j] += 2*depth;
+ if (node->t != (GameList[GameCnt].gmove & 0xFF)) {
+ if (best <= beta) {
+ killr3[ply] = mv;
+ } else {
+ if (mv != killr1[ply]) {
+ killr2[ply] = killr1[ply];
+ killr1[ply] = mv;
+ }
+ }
+ }
+ if (best > 9000) killr0[ply] = mv; else killr0[ply] = 0;
+ }
+ return(best);
+}
+
+
+int evaluate(side,xside,ply,depth,alpha,beta)
+short side,xside,ply,depth,alpha,beta;
+
+/*
+ Compute an estimate of the score by adding the positional score from
+ the previous ply to the material difference. If this score falls
+ inside a window which is 180 points wider than the alpha-beta window
+ (or within a 50 point window during quiescence search) call
+ ScorePosition() to determine a score, otherwise return the estimated
+ score. If one side has only a king and the other either has no pawns
+ or no pieces then the function ScoreLoneKing() is called.
+*/
+
+{
+register short evflag;
+
+ Xscore = -Pscore[ply-1] - INCscore + mtl[side] - mtl[xside];
+ hung[white] = hung[black] = 0;
+ slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) ||
+ (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0)));
+
+ if (slk) evflag = false;
+ else evflag =
+ (ply == 1 || ply < Sdepth ||
+ (depth == 0 && Xscore > alpha-xwndw && Xscore < beta+xwndw) ||
+ (depth < 0 && Xscore > alpha-25 && Xscore < beta+25));
+
+ if (evflag)
+ {
+ EvalNodes++;
+ ataks(side,atak[side]);
+ if (atak[side][PieceList[xside][0]] > 0) return(10001-ply);
+ ataks(xside,atak[xside]);
+ InChk = (atak[xside][PieceList[side][0]] > 0);
+ ScorePosition(side,&Xscore);
+ }
+ else
+ {
+ if (SqAtakd(PieceList[xside][0],side)) return(10001-ply);
+ InChk = SqAtakd(PieceList[side][0],xside);
+ if (slk) ScoreLoneKing(side,&Xscore);
+ }
+
+ Pscore[ply] = Xscore - mtl[side] + mtl[xside];
+ if (InChk) ChkFlag[ply-1] = Pindex[TOsquare];
+ else ChkFlag[ply-1] = 0;
+ return(Xscore);
+}
+
+
+int ProbeTTable(side,depth,alpha,beta,score)
+short side,depth,*alpha,*beta,*score;
+
+/*
+ Look for the current board position in the transposition table.
+*/
+
+{
+short hindx;
+ if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
+ hindx = (hashkey & (ttblsz-1));
+ ptbl = (ttable + hindx);
+ if (ptbl->depth >= depth && ptbl->hashbd == hashbd)
+ {
+ HashCnt++;
+ PV = ptbl->mv;
+ if (ptbl->flags & truescore)
+ {
+ *score = ptbl->score;
+ *beta = -20000;
+ return(true);
+ }
+/*
+ else if (ptbl->flags & upperbound)
+ {
+ if (ptbl->score < *beta) *beta = ptbl->score+1;
+ }
+*/
+ else if (ptbl->flags & lowerbound)
+ {
+ if (ptbl->score > *alpha) *alpha = ptbl->score-1;
+ }
+ }
+ return(false);
+}
+
+
+void PutInTTable(side,score,depth,alpha,beta,mv)
+short side,score,depth,alpha,beta;
+unsigned short mv;
+
+/*
+ Store the current board position in the transposition table.
+*/
+
+{
+short hindx;
+ if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
+ hindx = (hashkey & (ttblsz-1));
+ ptbl = (ttable + hindx);
+ ptbl->hashbd = hashbd;
+ ptbl->depth = depth;
+ ptbl->score = score;
+ ptbl->mv = mv;
+ ptbl->flags = 0;
+ if (score < alpha) ptbl->flags |= upperbound;
+ else if (score > beta) ptbl->flags |= lowerbound;
+ else ptbl->flags |= truescore;
+}
+
+
+void ZeroTTable()
+{
+int i;
+ if (hashflag)
+ for (i = 0; i < ttblsz; i++)
+ {
+ ptbl = (ttable + i);
+ ptbl->depth = 0;
+ }
+}
+
+
+void MoveList(side,ply)
+short side,ply;
+
+/*
+ Fill the array Tree[] with all available moves for side to play. Array
+ TrPnt[ply] contains the index into Tree[] of the first move at a ply.
+*/
+
+{
+register short i,xside,f;
+
+ xside = otherside[side];
+ if (PV == 0) Swag0 = killr0[ply]; else Swag0 = PV;
+ Swag1 = killr1[ply]; Swag2 = killr2[ply];
+ Swag3 = killr3[ply]; Swag4 = 0;
+ if (ply > 2) Swag4 = killr1[ply-2];
+ TrPnt[ply+1] = TrPnt[ply];
+ Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
+ for (i = PieceCnt[side]; i >= 0; i--)
+ GenMoves(ply,PieceList[side][i],side,xside);
+ if (kingmoved[side] == 0 && !castld[side])
+ {
+ f = PieceList[side][0];
+ if (castle(side,f,f+2,0))
+ {
+ LinkMove(ply,f,f+2,xside);
+ Tree[TrPnt[ply+1]-1].flags |= cstlmask;
+ }
+ if (castle(side,f,f-2,0))
+ {
+ LinkMove(ply,f,f-2,xside);
+ Tree[TrPnt[ply+1]-1].flags |= cstlmask;
+ }
+ }
+}
+
+
+void GenMoves(ply,sq,side,xside)
+short ply,sq,side,xside;
+
+/*
+ Generate moves for a piece. The from square is mapped onto a special
+ board and offsets (taken from array Dir[]) are added to the mapped
+ location. The newly generated square is tested to see if it falls off
+ the board by ANDing the square with 88 HEX. Legal moves are linked
+ into the tree.
+*/
+
+{
+register short m,u,d,i,m0,piece;
+
+ piece = board[sq]; m0 = map[sq];
+ if (sweep[piece])
+ for (i = Dstart[piece]; i <= Dstop[piece]; i++)
+ {
+ d = Dir[i]; m = m0+d;
+ while (!(m & 0x88))
+ {
+ u = unmap[m];
+ if (color[u] == neutral)
+ {
+ LinkMove(ply,sq,u,xside);
+ m += d;
+ }
+ else if (color[u] == xside)
+ {
+ LinkMove(ply,sq,u,xside);
+ break;
+ }
+ else break;
+ }
+ }
+ else if (piece == pawn)
+ {
+ if (side == white && color[sq+8] == neutral)
+ {
+ LinkMove(ply,sq,sq+8,xside);
+ if (row[sq] == 1)
+ if (color[sq+16] == neutral)
+ LinkMove(ply,sq,sq+16,xside);
+ }
+ else if (side == black && color[sq-8] == neutral)
+ {
+ LinkMove(ply,sq,sq-8,xside);
+ if (row[sq] == 6)
+ if (color[sq-16] == neutral)
+ LinkMove(ply,sq,sq-16,xside);
+ }
+ for (i = Dstart[piece]; i <= Dstop[piece]; i++)
+ if (!((m = m0+Dir[i]) & 0x88))
+ {
+ u = unmap[m];
+ if (color[u] == xside || u == epsquare)
+ LinkMove(ply,sq,u,xside);
+ }
+ }
+ else
+ {
+ for (i = Dstart[piece]; i <= Dstop[piece]; i++)
+ if (!((m = m0+Dir[i]) & 0x88))
+ {
+ u = unmap[m];
+ if (color[u] != side) LinkMove(ply,sq,u,xside);
+ }
+ }
+}
+
+
+void LinkMove(ply,f,t,xside)
+short ply,f,t,xside;
+
+/*
+ Add a move to the tree. Assign a bonus to order the moves
+ as follows:
+ 1. Principle variation
+ 2. Capture of last moved piece
+ 3. Other captures (major pieces first)
+ 4. Killer moves
+ 5. "history" killers
+*/
+
+{
+register short s,z;
+register unsigned short mv;
+struct leaf *node;
+
+ node = &Tree[TrPnt[ply+1]];
+ ++TrPnt[ply+1];
+ node->flags = 0;
+ node->f = f; node->t = t;
+ mv = (f<<8) + t;
+ s = 0;
+ if (mv == Swag0) s = 2000;
+ else if (mv == Swag1) s = 60;
+ else if (mv == Swag2) s = 50;
+ else if (mv == Swag3) s = 40;
+ else if (mv == Swag4) s = 30;
+ if (color[t] != neutral)
+ {
+ node->flags |= capture;
+ if (t == TOsquare) s += 500;
+ s += value[board[t]] - board[f];
+ }
+ if (board[f] == pawn) {
+ if (row[t] == 0 || row[t] == 7) {
+ node->flags |= promote;
+ s += 800;
+ } else {
+ if (row[t] == 1 || row[t] == 6) {
+ node->flags |= pwnthrt;
+ s += 600;
+ } else {
+ if (t == epsquare) node->flags |= epmask;
+ }
+ }
+ }
+ z = (f<<6) + t; if (xside == white) z |= 0x1000;
+ s += history[z];
+ node->score = s - 20000;
+}
+
+
+void CaptureList(side,xside,ply)
+short side,xside,ply;
+
+/*
+ Generate captures and Pawn promotions only.
+*/
+
+#define LinkCapture \
+{\
+ node->f = sq; node->t = u;\
+ node->flags = capture;\
+ node->score = value[board[u]] + svalue[board[u]] - piece;\
+ if (piece == pawn && (u < 8 || u > 55))\
+ {\
+ node->flags |= promote;\
+ node->score = valueQ;\
+ }\
+ ++node;\
+ ++TrPnt[ply+1];\
+}
+
+{
+register short m,u,d,sq,m0;
+short i,j,j1,j2,r7,d0,piece,*PL;
+struct leaf *node;
+
+ TrPnt[ply+1] = TrPnt[ply];
+ node = &Tree[TrPnt[ply]];
+ Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
+ if (side == white)
+ {
+ r7 = 6; d0 = 8;
+ }
+ else
+ {
+ r7 = 1; d0 = -8;
+ }
+ PL = PieceList[side];
+ for (i = 0; i <= PieceCnt[side]; i++)
+ {
+ sq = PL[i];
+ m0 = map[sq]; piece = board[sq];
+ j1 = Dstart[piece]; j2 = Dstop[piece];
+ if (sweep[piece])
+ for (j = j1; j <= j2; j++)
+ {
+ d = Dir[j]; m = m0+d;
+ while (!(m & 0x88))
+ {
+ u = unmap[m];
+ if (color[u] == neutral) m += d;
+ else
+ {
+ if (color[u] == xside) LinkCapture;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (j = j1; j <= j2; j++)
+ if (!((m = m0+Dir[j]) & 0x88))
+ {
+ u = unmap[m];
+ if (color[u] == xside) LinkCapture;
+ }
+ if (piece == pawn && row[sq] == r7)
+ {
+ u = sq+d0;
+ if (color[u] == neutral) LinkCapture;
+ }
+ }
+ }
+}
+
+
+int castle(side,kf,kt,iop)
+short side,kf,kt,iop;
+
+/*
+ Make or Unmake a castling move.
+*/
+
+{
+register short rf,rt,d,t0,xside;
+
+ xside = otherside[side];
+ if (kt > kf)
+ {
+ rf = kf+3; rt = kt-1; d = 1;
+ }
+ else
+ {
+ rf = kf-4; rt = kt+1; d = -1;
+ }
+ if (iop == 0)
+ {
+ if (board[kf] != king || board[rf] != rook || color[rf] != side)
+ return(false);
+ if (color[kt] != neutral || color[rt] != neutral) return(false);
+ if (d == -1 && color[kt+d] != neutral) return(false);
+ if (SqAtakd(kf,xside)) return(false);
+ if (SqAtakd(kt,xside)) return(false);
+ if (SqAtakd(kf+d,xside)) return(false);
+ }
+ else
+ {
+ if (iop == 1) castld[side] = true; else castld[side] = false;
+ if (iop == 2)
+ {
+ t0 = kt; kt = kf; kf = t0;
+ t0 = rt; rt = rf; rf = t0;
+ }
+ board[kt] = king; color[kt] = side; Pindex[kt] = 0;
+ board[kf] = no_piece; color[kf] = neutral;
+ board[rt] = rook; color[rt] = side; Pindex[rt] = Pindex[rf];
+ board[rf] = no_piece; color[rf] = neutral;
+ PieceList[side][Pindex[kt]] = kt;
+ PieceList[side][Pindex[rt]] = rt;
+ if (hashflag)
+ {
+ UpdateHashbd(side,king,kf,kt);
+ UpdateHashbd(side,rook,rf,rt);
+ }
+ }
+ return(true);
+}
+
+
+void EnPassant(xside,f,t,iop)
+short xside,f,t,iop;
+
+/*
+ Make or unmake an en passant move.
+*/
+
+{
+register short l;
+ if (t > f) l = t-8; else l = t+8;
+ if (iop == 1)
+ {
+ board[l] = no_piece; color[l] = neutral;
+ }
+ else
+ {
+ board[l] = pawn; color[l] = xside;
+ }
+ InitializeStats();
+}
+
+
+void MakeMove(side,node,tempb,tempc,tempsf,tempst)
+short side,*tempc,*tempb,*tempsf,*tempst;
+struct leaf *node;
+
+/*
+ Update Arrays board[], color[], and Pindex[] to reflect the new board
+ position obtained after making the move pointed to by node. Also
+ update miscellaneous stuff that changes when a move is made.
+*/
+
+{
+register short f,t,xside,ct,cf;
+
+ xside = otherside[side];
+ f = node->f; t = node->t; epsquare = -1;
+ FROMsquare = f; TOsquare = t;
+ INCscore = 0;
+ GameList[++GameCnt].gmove = (f<<8) + t;
+ if (node->flags & cstlmask)
+ {
+ GameList[GameCnt].piece = no_piece;
+ GameList[GameCnt].color = side;
+ castle(side,f,t,1);
+ }
+ else
+ {
+ *tempc = color[t]; *tempb = board[t];
+ *tempsf = svalue[f]; *tempst = svalue[t];
+ GameList[GameCnt].piece = *tempb;
+ GameList[GameCnt].color = *tempc;
+ if (*tempc != neutral)
+ {
+ UpdatePieceList(*tempc,t,1);
+ if (*tempb == pawn) --PawnCnt[*tempc][column[t]];
+ if (board[f] == pawn)
+ {
+ --PawnCnt[side][column[f]];
+ ++PawnCnt[side][column[t]];
+ cf = column[f]; ct = column[t];
+ if (PawnCnt[side][ct] > 1+PawnCnt[side][cf])
+ INCscore -= 15;
+ else if (PawnCnt[side][ct] < 1+PawnCnt[side][cf])
+ INCscore += 15;
+ else if (ct == 0 || ct == 7 || PawnCnt[side][ct+ct-cf] == 0)
+ INCscore -= 15;
+ }
+ mtl[xside] -= value[*tempb];
+ if (*tempb == pawn) pmtl[xside] -= valueP;
+ if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
+ INCscore += *tempst;
+ }
+ color[t] = color[f]; board[t] = board[f]; svalue[t] = svalue[f];
+ Pindex[t] = Pindex[f]; PieceList[side][Pindex[t]] = t;
+ color[f] = neutral; board[f] = no_piece;
+ if (board[t] == pawn) {
+ if (t-f == 16) {
+ epsquare = f+8;
+ } else {
+ if (f-t == 16) epsquare = f-8;
+ }
+ }
+ if (node->flags & promote)
+ {
+ board[t] = queen;
+ --PawnCnt[side][column[t]];
+ mtl[side] += valueQ - valueP;
+ pmtl[side] -= valueP;
+ HasQueen[side] = true;
+ if (hashflag)
+ {
+ UpdateHashbd(side,pawn,f,-1);
+ UpdateHashbd(side,queen,f,-1);
+ }
+ INCscore -= *tempsf;
+ }
+ if (board[t] == king) ++kingmoved[side];
+ if (node->flags & epmask) EnPassant(xside,f,t,1);
+ else if (hashflag) UpdateHashbd(side,board[t],f,t);
+ }
+}
+
+
+void UnmakeMove(side,node,tempb,tempc,tempsf,tempst)
+short side,*tempc,*tempb,*tempsf,*tempst;
+struct leaf *node;
+
+/*
+ Take back a move.
+*/
+
+{
+register short f,t,xside;
+
+ xside = otherside[side];
+ f = node->f; t = node->t; epsquare = -1;
+ GameCnt--;
+ if (node->flags & cstlmask) castle(side,f,t,2);
+ else
+ {
+ color[f] = color[t]; board[f] = board[t]; svalue[f] = *tempsf;
+ Pindex[f] = Pindex[t]; PieceList[side][Pindex[f]] = f;
+ color[t] = *tempc; board[t] = *tempb; svalue[t] = *tempst;
+ if (node->flags & promote)
+ {
+ board[f] = pawn;
+ ++PawnCnt[side][column[t]];
+ mtl[side] += valueP - valueQ;
+ pmtl[side] += valueP;
+ if (hashflag)
+ {
+ UpdateHashbd(side,queen,-1,t);
+ UpdateHashbd(side,pawn,-1,t);
+ }
+ }
+ if (*tempc != neutral)
+ {
+ UpdatePieceList(*tempc,t,2);
+ if (*tempb == pawn) ++PawnCnt[*tempc][column[t]];
+ if (board[f] == pawn)
+ {
+ --PawnCnt[side][column[t]];
+ ++PawnCnt[side][column[f]];
+ }
+ mtl[xside] += value[*tempb];
+ if (*tempb == pawn) pmtl[xside] += valueP;
+ if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
+ }
+ if (board[f] == king) --kingmoved[side];
+ if (node->flags & epmask) EnPassant(xside,f,t,2);
+ else if (hashflag) UpdateHashbd(side,board[f],f,t);
+ }
+}
+
+
+void UpdateHashbd(side,piece,f,t)
+short side,piece,f,t;
+
+/*
+ hashbd contains a 32 bit "signature" of the board position. hashkey
+ contains a 16 bit code used to address the hash table. When a move is
+ made, XOR'ing the hashcode of moved piece on the from and to squares
+ with the hashbd and hashkey values keeps things current.
+*/
+
+{
+ if (f >= 0)
+ {
+ hashbd ^= hashcode[side][piece][f].bd;
+ hashkey ^= hashcode[side][piece][f].key;
+ }
+ if (t >= 0)
+ {
+ hashbd ^= hashcode[side][piece][t].bd;
+ hashkey ^= hashcode[side][piece][t].key;
+ }
+}
+
+
+void UpdatePieceList(side,sq,iop)
+short side,sq,iop;
+
+/*
+ Update the PieceList and Pindex arrays when a piece is captured or
+ when a capture is unmade.
+*/
+
+{
+register short i;
+ if (iop == 1)
+ {
+ PieceCnt[side]--;
+ for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
+ {
+ PieceList[side][i] = PieceList[side][i+1];
+ Pindex[PieceList[side][i]] = i;
+ }
+ }
+ else
+ {
+ PieceCnt[side]++;
+ PieceList[side][PieceCnt[side]] = sq;
+ Pindex[sq] = PieceCnt[side];
+ }
+}
+
+
+void InitializeStats()
+
+/*
+ Scan thru the board seeing what's on each square. If a piece is found,
+ update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
+ determine the material for each side and set the hashkey and hashbd
+ variables to represent the current board position. Array
+ PieceList[side][indx] contains the location of all the pieces of
+ either side. Array Pindex[sq] contains the indx into PieceList for a
+ given square.
+*/
+
+{
+register short i,sq;
+ epsquare = -1;
+ for (i = 0; i < 8; i++)
+ PawnCnt[white][i] = PawnCnt[black][i] = 0;
+ mtl[white] = mtl[black] = pmtl[white] = pmtl[black] = 0;
+ PieceCnt[white] = PieceCnt[black] = 0;
+ hashbd = hashkey = 0;
+ for (sq = 0; sq < 64; sq++)
+ if (color[sq] != neutral)
+ {
+ mtl[color[sq]] += value[board[sq]];
+ if (board[sq] == pawn)
+ {
+ pmtl[color[sq]] += valueP;
+ ++PawnCnt[color[sq]][column[sq]];
+ }
+ if (board[sq] == king) Pindex[sq] = 0;
+ else Pindex[sq] = ++PieceCnt[color[sq]];
+ PieceList[color[sq]][Pindex[sq]] = sq;
+ hashbd ^= hashcode[color[sq]][board[sq]][sq].bd;
+ hashkey ^= hashcode[color[sq]][board[sq]][sq].key;
+ }
+}
+
+
+void pick(p1,p2)
+short p1,p2;
+
+/*
+ Find the best move in the tree between indexes p1 and p2. Swap the
+ best move into the p1 element.
+*/
+
+{
+register short p,s,p0,s0;
+struct leaf temp;
+
+ s0 = Tree[p1].score; p0 = p1;
+ for (p = p1+1; p <= p2; p++)
+ if ((s = Tree[p].score) > s0)
+ {
+ s0 = s; p0 = p;
+ }
+ if (p0 != p1)
+ {
+ temp = Tree[p1]; Tree[p1] = Tree[p0]; Tree[p0] = temp;
+ }
+}
+
+
+void repetition(cnt)
+short *cnt;
+
+/*
+ Check for draw by threefold repetition.
+*/
+
+{
+register short i,c,f,t;
+short b[64];
+unsigned short m;
+ *cnt = c = 0;
+ if (GameCnt > Game50+3)
+ {
+ for (i = 0; i < 64; b[i++] = 0);
+ for (i = GameCnt; i > Game50; i--)
+ {
+ m = GameList[i].gmove; f = m>>8; t = m & 0xFF;
+ if (++b[f] == 0) c--; else c++;
+ if (--b[t] == 0) c--; else c++;
+ if (c == 0) (*cnt)++;
+ }
+ }
+}
+
+
+int SqAtakd(sq,side)
+short sq,side;
+
+/*
+ See if any piece with color 'side' ataks sq. First check for pawns
+ or king, then try other pieces. Array Dcode is used to check for
+ knight attacks or R,B,Q co-linearity.
+*/
+
+{
+register short m,d,m0,m1,i,loc,piece,*PL;
+
+ m1 = map[sq];
+ if (side == white) m = m1-0x0F; else m = m1+0x0F;
+ if (!(m & 0x88))
+ if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
+ if (side == white) m = m1-0x11; else m = m1+0x11;
+ if (!(m & 0x88))
+ if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
+ if (distance(sq,PieceList[side][0]) == 1) return(true);
+
+ PL = PieceList[side];
+ for (i = 1; i <= PieceCnt[side]; i++)
+ {
+ loc = PL[i]; piece = board[loc];
+ if (piece == pawn) continue;
+ m0 = map[loc]; d = Dcode[abs(m1-m0)];
+ if (d == 0 || (Pdir[d] & pbit[piece]) == 0) continue;
+ if (piece == knight) return(true);
+ else
+ {
+ if (m1 < m0) d = -d;
+ for (m = m0+d; m != m1; m += d)
+ if (color[unmap[m]] != neutral) break;
+ if (m == m1) return(true);
+ }
+ }
+ return(false);
+}
+
+
+void ataks(side,a)
+short side,*a;
+
+/*
+ Fill array atak[][] with info about ataks to a square. Bits 8-15
+ are set if the piece (king..pawn) ataks the square. Bits 0-7
+ contain a count of total ataks to the square.
+*/
+
+{
+register short u,m,d,c,m0;
+short j,j1,j2,piece,i,sq,*PL;
+
+ for (u = 0; u < 64; a[u++] = 0);
+ Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
+ PL = PieceList[side];
+ for (i = 0; i <= PieceCnt[side]; i++)
+ {
+ sq = PL[i];
+ m0 = map[sq];
+ piece = board[sq];
+ c = control[piece]; j1 = Dstart[piece]; j2 = Dstop[piece];
+ if (sweep[piece])
+ for (j = j1; j <= j2; j++)
+ {
+ d = Dir[j]; m = m0+d;
+ while (!(m & 0x88))
+ {
+ u = unmap[m];
+ a[u] = ++a[u] | c;
+ if (color[u] == neutral) m += d;
+ else break;
+ }
+ }
+ else
+ for (j = j1; j <= j2; j++)
+ if (!((m = m0+Dir[j]) & 0x88))
+ {
+ u = unmap[m];
+ a[u] = ++a[u] | c;
+ }
+ }
+}
+
+
+
+void ElapsedTime(iop)
+
+/*
+ Determine the time that has passed since the search was started. If
+ the elapsed time exceeds the target (ResponseTime+ExtraTime) then set
+ timeout to true which will terminate the search.
+*/
+
+short iop;
+{
+ /*et = time((long *)0) - time0;*/
+ et = *(rb->current_tick) / HZ - time0;
+ if (et < 0) et = 0;
+ ETnodes += 50;
+ if (et > et0 || iop == 1)
+ {
+ if (et > ResponseTime+ExtraTime && Sdepth > 1) timeout = true;
+ et0 = et;
+ if (iop == 1)
+ {
+ /*time0 = time((long *)0);*/
+ time0 = *(rb->current_tick) / HZ ;
+ et0 = 0;
+ }
+ /*(void) times(&tmbuf2);
+ cputimer = 100*(tmbuf2.tms_utime - tmbuf1.tms_utime) / HZ;
+ if (cputimer > 0) evrate = (100*NodeCnt)/(cputimer+100*ft);
+ else evrate = 0;*/
+ ETnodes = NodeCnt + 50;
+ /*UpdateClocks();*/
+ }
+}
+
+
+
+void SetTimeControl( void )
+{
+ if (TCflag)
+ {
+ TimeControl.moves[white] = TimeControl.moves[black] = TCmoves;
+ TimeControl.clock[white] = TimeControl.clock[black] = 60*(long)TCminutes;
+ }
+ else
+ {
+ TimeControl.moves[white] = TimeControl.moves[black] = 0;
+ TimeControl.clock[white] = TimeControl.clock[black] = 0;
+ Level = 60*(long)TCminutes;
+ }
+ et = 0;
+ ElapsedTime(1);
+}
+
+
+
+/* ............ INTERFACE ROUTINES ........................... */
+
+/*static void VoidFunction ( void ) {
+ while (!(quit))
+ {
+ if (bothsides && !mate) SelectMove(opponent,1); else InputCommand();
+ if (!(quit || mate || force)) SelectMove(computer,1);
+ }
+ ExitChess();
+}*/
+
+int VerifyMove(char s[],short iop,unsigned short *mv)
+
+/*
+ Compare the string 's' to the list of legal moves available for the
+ opponent. If a match is found, make the move on the board.
+*/
+
+{
+static short pnt,tempb,tempc,tempsf,tempst,cnt;
+static struct leaf xnode;
+struct leaf *node;
+
+ *mv = 0;
+ if (iop == 2)
+ {
+ UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
+ return(false);
+ }
+ cnt = 0;
+ MoveList(opponent,2);
+ pnt = TrPnt[2];
+ while (pnt < TrPnt[3])
+ {
+ node = &Tree[pnt++];
+ algbr(node->f,node->t,node->flags & cstlmask);
+ if (rb->strcmp(s,mvstr1) == 0 || rb->strcmp(s,mvstr2) == 0 ||
+ rb->strcmp(s,mvstr3) == 0)
+ {
+ cnt++; xnode = *node;
+ }
+ }
+ if (cnt == 1)
+ {
+ MakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
+ if (SqAtakd(PieceList[opponent][0],computer))
+ {
+ UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
+ /*ShowMessage("Illegal Move!!");*/
+ return(false);
+ }
+ else
+ {
+ if (iop == 1) return(true);
+ /*if (xnode.flags & epmask) UpdateDisplay(0,0,1,0);
+ else UpdateDisplay(xnode.f,xnode.t,0,xnode.flags & cstlmask);*/
+ if (xnode.flags & cstlmask) Game50 = GameCnt;
+ else if (board[xnode.t] == pawn || (xnode.flags & capture))
+ Game50 = GameCnt;
+ GameList[GameCnt].depth = GameList[GameCnt].score = 0;
+ GameList[GameCnt].nodes = 0;
+ ElapsedTime(1);
+ GameList[GameCnt].time = (short)et;
+ TimeControl.clock[opponent] -= et;
+ --TimeControl.moves[opponent];
+ *mv = (xnode.f << 8) + xnode.t;
+ algbr(xnode.f,xnode.t,false);
+ return(true);
+ }
+ }
+ /*if (cnt > 1) ShowMessage("Ambiguous Move!");*/
+ return(false);
+}
+
+
+/* ---- Reset the board and other variables to start a new game. ---- */
+void NewGame() {
+ short l,r,c,p;
+
+ mate = quit = reverse = bothsides = post = false;
+ hashflag = force = PawnStorm = false;
+ easy = beep = rcptr = true;
+ lpost = NodeCnt = epsquare = et0 = 0;
+ dither = 0;
+ Awindow = 90;
+ Bwindow = 90;
+ xwndw = 90;
+ MaxSearchDepth = 29;
+ contempt = 0;
+ GameCnt = -1; Game50 = 0;
+ Zwmtl = Zbmtl = 0;
+ Developed[white] = Developed[black] = false;
+ castld[white] = castld[black] = false;
+ kingmoved[white] = kingmoved[black] = 0;
+ PawnThreat[0] = CptrFlag[0] = Threat[0] = false;
+ Pscore[0] = 12000; Tscore[0] = 12000;
+ opponent = white; computer = black;
+ for (r = 0; r < 8; r++)
+ for (c = 0; c < 8; c++)
+ {
+ l = 8*r+c; locn[r][c] = l;
+ row[l] = r; column[l] = c;
+ board[l] = Stboard[l]; color[l] = Stcolor[l];
+ }
+ for (c = white; c <= black; c++)
+ for (p = pawn; p <= king; p++)
+ for (l = 0; l < 64; l++)
+ {
+ hashcode[c][p][l].key = (unsigned short)rb->rand();
+ hashcode[c][p][l].bd = ((unsigned long)rb->rand() << 16) +
+ (unsigned long)rb->rand();
+ }
+ if (TCflag) SetTimeControl();
+ /*else if (Level == 0) SelectLevel();*/
+ /*UpdateDisplay(0,0,1,0);*/
+ InitializeStats();
+ /*time0 = time((long *)0);*/
+ time0 = *(rb->current_tick) / HZ ;
+ ElapsedTime(1);
+ /*GetOpenings();*/
+}
+
+/* ---- Initialize variables and reset board ---- */
+void GNUChess_Initialize ( void ) {
+ int buffer_size;
+ /* no malloc sir, 64K should be enough for now */
+ /*char ttablearray[65536];*/
+ /*ttable = (struct hashentry *)ttablearray;*/
+ /*ttable = (struct hashentry *)malloc(ttblsz *
+ (unsigned long)sizeof(struct hashentry));*/
+ buffer_size = ttblsz * sizeof(struct hashentry);
+ ttable = rb->plugin_get_buffer( &buffer_size );
+ Level = 1;
+ OperatorTime = 0;
+ TCmoves = 60;
+ TCminutes = 5;
+ TCflag = true;
+ NewGame();
+ MaxSearchDepth = 29 ;
+ /* remember to GetOpenings */
+}
+
+void algbr(f,t,flag)
+short f,t,flag;
+{
+ mvstr1[0] = cxx[column[f]]; mvstr1[1] = rxx[row[f]];
+ mvstr1[2] = cxx[column[t]]; mvstr1[3] = rxx[row[t]];
+ mvstr2[0] = qxx[board[f]];
+ mvstr2[1] = mvstr1[2]; mvstr2[2] = mvstr1[3];
+ mvstr1[4] = '\0'; mvstr2[3] = '\0';
+ if (flag) {
+ if (t > f) {
+ rb->strcpy(mvstr2,"o-o");
+ } else {
+ rb->strcpy(mvstr2,"o-o-o");
+ }
+ }
+
+ if (board[f] == pawn) mvstr3[0] = mvstr1[0];
+ else mvstr3[0] = qxx[board[f]];
+ if (color[t] != neutral)
+ {
+ mvstr3[1] = ':';
+ mvstr3[2] = mvstr1[2];
+ mvstr3[3] = mvstr1[3];
+ mvstr3[4] = '\0';
+ }
+ else if (board[f] == pawn)
+ {
+ mvstr3[1] = mvstr1[3];
+ mvstr3[2] = '\0';
+ }
+ else
+ {
+ mvstr3[1] = mvstr1[0];
+ mvstr3[2] = mvstr1[1];
+ mvstr3[3] = mvstr1[2];
+ mvstr3[4] = mvstr1[3];
+ mvstr3[5] = '\0';
+ }
+}
diff --git a/apps/plugins/chessbox/gnuchess.h b/apps/plugins/chessbox/gnuchess.h
new file mode 100644
index 0000000..6ea77dc
--- /dev/null
+++ b/apps/plugins/chessbox/gnuchess.h
@@ -0,0 +1,37 @@
+
+#ifndef _GNUCHESS_H_
+#define _GNUCHESS_H_
+
+#define neutral 2
+#define white 0
+#define black 1
+#define no_piece 0
+#define pawn 1
+#define knight 2
+#define bishop 3
+#define rook 4
+#define queen 5
+#define king 6
+#define valueP 100
+#define valueN 350
+#define valueB 355
+#define valueR 550
+#define valueQ 1100
+#define valueK 1200
+
+
+extern short mate,opponent,computer;
+extern short locn[8][8];
+extern short board[64];
+extern short color[64];
+extern long Level;
+extern short TCflag,TCmoves,TCminutes;
+
+
+void SetTimeControl(void);
+void GNUChess_Initialize(void);
+int VerifyMove(char s[],short iop,unsigned short *mv);
+int SelectMove ( short side, short iop);
+
+
+#endif
diff --git a/docs/CREDITS b/docs/CREDITS
index 447c7ae..5958d60 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -171,3 +171,4 @@ Mikael Magnusson
Dominik Wenger
Henrico Witvliet
Andrew Scott
+Miguel A. Arévalo