Check in Bonanza Feliz 0.0
authorH.G. Muller <h.g.muller@hccnet.nl>
Wed, 20 Oct 2010 17:52:29 +0000 (19:52 +0200)
committerH.G. Muller <h.g.muller@hccnet.nl>
Wed, 20 Oct 2010 17:52:29 +0000 (19:52 +0200)
51 files changed:
Makefile [new file with mode: 0644]
Makefile.vs [new file with mode: 0644]
attack.c [new file with mode: 0644]
bitop.c [new file with mode: 0644]
bonanza.ico [new file with mode: 0644]
bonanza.rc [new file with mode: 0644]
book.c [new file with mode: 0644]
book_anti.csa [new file with mode: 0644]
csa.c [new file with mode: 0644]
data.c [new file with mode: 0644]
debug.c [new file with mode: 0644]
dek.c [new file with mode: 0644]
evaldiff.c [new file with mode: 0644]
evaluate.c [new file with mode: 0644]
gencap.c [new file with mode: 0644]
genchk.c [new file with mode: 0644]
gendrop.c [new file with mode: 0644]
genevasn.c [new file with mode: 0644]
gennocap.c [new file with mode: 0644]
hash.c [new file with mode: 0644]
ini.c [new file with mode: 0644]
io.c [new file with mode: 0644]
iterate.c [new file with mode: 0644]
lan.txt [new file with mode: 0644]
learn1.c [new file with mode: 0644]
learn2.c [new file with mode: 0644]
main.c [new file with mode: 0644]
makemove.c [new file with mode: 0644]
mate1ply.c [new file with mode: 0644]
mate3.c [new file with mode: 0644]
movgenex.c [new file with mode: 0644]
next.c [new file with mode: 0644]
param.h [new file with mode: 0644]
phash.c [new file with mode: 0644]
ponder.c [new file with mode: 0644]
problem.c [new file with mode: 0644]
proce.c [new file with mode: 0644]
quiesrch.c [new file with mode: 0644]
rand.c [new file with mode: 0644]
readme.txt [new file with mode: 0644]
root.c [new file with mode: 0644]
sckt.c [new file with mode: 0644]
search.c [new file with mode: 0644]
searchr.c [new file with mode: 0644]
shogi.h [new file with mode: 0644]
swap.c [new file with mode: 0644]
thread.c [new file with mode: 0644]
time.c [new file with mode: 0644]
unmake.c [new file with mode: 0644]
utility.c [new file with mode: 0644]
valid.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..856e931
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+OBJS =data.o main.o io.o proce.o utility.o ini.o attack.o book.o makemove.o \
+      unmake.o time.o csa.o valid.o bitop.o iterate.o searchr.o search.o \
+      quiesrch.o evaluate.o swap.o  hash.o root.o next.o movgenex.o \
+      genevasn.o gencap.o gennocap.o gendrop.o mate1ply.o rand.o learn1.o \
+      learn2.o evaldiff.o problem.o ponder.o thread.o sckt.o debug.o mate3.o \
+      genchk.o phash.o
+
+# Compile Options
+#
+# -DNDEBUG (DEBUG)  builds release (debug) version of Bonanza.
+# -DMINIMUM         disables some auxiliary functions that are not necessary to
+#                   play a game, e.g., book composition and optimization of
+#                   evaluation function.
+# -DTLP             enables thread-level parallel search.
+# -DMPV             enables multi-PV search.
+# -DCSA_LAN         enables bonanza to talk CSA Shogi TCP/IP protcol.
+# -DMNJ_LAN         enables a client-mode of cluster computing.
+# -DNO_LOGGING      suppresses dumping log files.
+
+OPT =-DNDEBUG -DMINIMUM -DTLP -DCSA_LAN -DMNJ_LAN
+
+help:
+       @echo "try targets as:"
+       @echo
+       @echo "  gcc"
+       @echo "  icc"
+
+gcc:
+       $(MAKE) CC=gcc CFLAGS='-std=gnu99 -O3 -Wall $(OPT)' LDFLAG1='-lm -lpthread' bonanza
+
+icc:
+       $(MAKE) CC=icc CFLAGS='-w2 $(OPT) -std=gnu99 -O2 -ipo' LDFLAG1='-static -ipo -pthread' bonanza
+
+bonanza : $(OBJS)
+       $(CC) $(LDFLAG1) -o bonanza $(OBJS) $(LDFLAG2)
+
+$(OBJS) : shogi.h param.h
+
+.c.o :
+       $(CC) -c $(CFLAGS) $*.c
+
+clean :
+       rm *.o
+       rm -fr profdir
+       rm bonanza
diff --git a/Makefile.vs b/Makefile.vs
new file mode 100644 (file)
index 0000000..6a966ba
--- /dev/null
@@ -0,0 +1,55 @@
+help:
+       @echo try targets as:
+       @echo   cl
+       @echo   icl
+
+# Compile Options
+#
+# /DNDEBUG (DEBUG)  builds release (debug) version of Bonanza.
+# /DMINIMUM         disables some auxiliary functions that are not necessary to
+#                   play a game, e.g., book composition and optimization of
+#                   evaluation function.
+# /DTLP             enables thread-level parallel search.
+# /DMPV             enables multi-PV search.
+# /DCSA_LAN         enables bonanza to talk CSA Shogi TCP/IP protcol.
+# /DMNJ_LAN         enables a client-mode of distributed computing.
+# /DDEKUNOBOU       enables dekunobou interface (avairable only for Windows).
+# /DCSASHOGI        builds an engine for CSA Shogi (avairable only for
+#                   Windows).
+# /DNO_LOGGING      suppresses dumping log files.
+
+FLAG = /DNDEBUG /DMINIMUM /DTLP /DMPV /DCSASHOGI /DNO_LOGGING
+
+OBJS = data.obj main.obj io.obj proce.obj ini.obj utility.obj attack.obj\
+       gencap.obj gennocap.obj gendrop.obj genevasn.obj mate3.obj genchk.obj\
+       movgenex.obj makemove.obj unmake.obj time.obj csa.obj valid.obj\
+       next.obj search.obj searchr.obj book.obj iterate.obj quiesrch.obj\
+       swap.obj evaluate.obj root.obj hash.obj mate1ply.obj bitop.obj\
+       rand.obj learn1.obj learn2.obj evaldiff.obj problem.obj ponder.obj\
+       thread.obj dek.obj sckt.obj debug.obj phash.obj
+
+cl:
+       $(MAKE) -f Makefile.vs bonanza.exe CC="cl" LD="link"\
+               CFLAGS="$(FLAG) /MT /W4 /nologo /O2 /Ob2 /Gr /GS- /GL"\
+               LDFLAGS="/NOLOGO /out:bonanza.exe /LTCG"
+
+icl:
+       $(MAKE) -f Makefile.vs bonanza.exe CC="icl" LD="icl"\
+               CFLAGS="/nologo $(FLAG) /Wall /O2 /Qipo /Gr"\
+               LDFLAGS="/nologo /Febonanza.exe"
+
+bonanza.exe : $(OBJS) bonanza.res
+       $(LD) $(LDFLAGS) $(OBJS) bonanza.res User32.lib Ws2_32.lib
+
+$(OBJS)  : shogi.h param.h
+
+bonanza.res : bonanza.rc bonanza.ico
+       rc /fobonanza.res bonanza.rc
+
+.c.obj :
+       $(CC) $(CFLAGS) /c $*.c
+
+clean :
+       del /q *.obj
+       del /q *.res
+       del /q bonanza.exe
diff --git a/attack.c b/attack.c
new file mode 100644 (file)
index 0000000..2c9cf78
--- /dev/null
+++ b/attack.c
@@ -0,0 +1,319 @@
+#include <assert.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+
+unsigned int
+is_pinned_on_white_king( const tree_t * restrict ptree, int isquare,
+                       int idirec )
+{
+  unsigned int ubb_attacks;
+  bitboard_t bb_attacks, bb_attacker;
+
+  switch ( idirec )
+    {
+    case direc_rank:
+      ubb_attacks = AttackRank( isquare );
+      if ( ubb_attacks & (BB_WKING.p[aslide[isquare].ir0]) )
+       {
+         return ubb_attacks & BB_B_RD.p[aslide[isquare].ir0];
+       }
+      break;
+
+    case direc_file:
+      bb_attacks = AttackFile( isquare );
+      if ( BBContract( bb_attacks, BB_WKING ) )
+       {
+         BBAnd( bb_attacker, BB_BLANCE, abb_plus_rays[isquare] );
+         BBOr( bb_attacker, bb_attacker, BB_B_RD );
+         return BBContract( bb_attacks, bb_attacker );  /* return! */
+       }
+      break;
+
+    case direc_diag1:
+      bb_attacks = AttackDiag1( isquare );
+      if ( BBContract( bb_attacks, BB_WKING ) )
+       {
+         return BBContract( bb_attacks, BB_B_BH );      /* return! */
+       }
+      break;
+
+    default:
+      assert( idirec == direc_diag2 );
+      bb_attacks = AttackDiag2( isquare );
+      if ( BBContract( bb_attacks, BB_WKING ) )
+       {
+         return BBContract( bb_attacks, BB_B_BH );      /* return! */
+       }
+      break;
+    }
+  
+  return 0;
+}
+
+
+unsigned int
+is_pinned_on_black_king( const tree_t * restrict ptree, int isquare,
+                       int idirec )
+{
+  unsigned int ubb_attacks;
+  bitboard_t bb_attacks, bb_attacker;
+
+  switch ( idirec )
+    {
+    case direc_rank:
+      ubb_attacks = AttackRank( isquare );
+      if ( ubb_attacks & (BB_BKING.p[aslide[isquare].ir0]) )
+       {
+         return ubb_attacks & BB_W_RD.p[aslide[isquare].ir0];
+       }
+      break;
+
+    case direc_file:
+      bb_attacks = AttackFile( isquare );
+      if ( BBContract( bb_attacks, BB_BKING ) )
+       {
+         BBAnd( bb_attacker, BB_WLANCE, abb_minus_rays[isquare] );
+         BBOr( bb_attacker, bb_attacker, BB_W_RD );
+         return BBContract( bb_attacks, bb_attacker );      /* return! */
+       }
+      break;
+
+    case direc_diag1:
+      bb_attacks = AttackDiag1( isquare );
+      if ( BBContract( bb_attacks, BB_BKING ) )
+       {
+         return BBContract( bb_attacks, BB_W_BH );          /* return! */
+       }
+      break;
+
+    default:
+      assert( idirec == direc_diag2 );
+      bb_attacks = AttackDiag2( isquare );
+      if ( BBContract( bb_attacks, BB_BKING ) )
+       {
+         return BBContract( bb_attacks, BB_W_BH );          /* return! */
+       }
+      break;
+    }
+  return 0;
+}
+
+
+/* perpetual check detections are omitted. */
+int
+is_mate_b_pawn_drop( tree_t * restrict ptree, int sq_drop )
+{
+  bitboard_t bb, bb_sum, bb_move;
+  int iwk, ito, iret, ifrom, idirec;
+
+  BBAnd( bb_sum, BB_WKNIGHT, abb_b_knight_attacks[sq_drop] );
+
+  BBAndOr( bb_sum, BB_WSILVER, abb_b_silver_attacks[sq_drop] );
+  BBAndOr( bb_sum, BB_WTGOLD, abb_b_gold_attacks[sq_drop] );
+
+  AttackBishop( bb, sq_drop );
+  BBAndOr( bb_sum, BB_W_BH, bb );
+
+  AttackRook( bb, sq_drop );
+  BBAndOr( bb_sum, BB_W_RD, bb );
+
+  BBOr( bb, BB_WHORSE, BB_WDRAGON );
+  BBAndOr( bb_sum, bb, abb_king_attacks[sq_drop] );
+
+  while ( BBToU( bb_sum ) )
+    {
+      ifrom  = FirstOne( bb_sum );
+      Xor( ifrom, bb_sum );
+
+      if ( IsDiscoverWK( ifrom, sq_drop ) ) { continue; }
+      return 0;
+    }
+
+  iwk  = SQ_WKING;
+  iret = 1;
+  Xor( sq_drop, BB_BOCCUPY );
+  XorFile( sq_drop, OCCUPIED_FILE );
+  XorDiag2( sq_drop, OCCUPIED_DIAG2 );
+  XorDiag1( sq_drop, OCCUPIED_DIAG1 );
+  
+  BBNot( bb_move, BB_WOCCUPY );
+  BBAnd( bb_move, bb_move, abb_king_attacks[iwk] );
+  while ( BBToU( bb_move ) )
+    {
+      ito = FirstOne( bb_move );
+      if ( ! is_white_attacked( ptree, ito ) )
+       {
+         iret = 0;
+         break;
+       }
+      Xor( ito, bb_move );
+    }
+
+  Xor( sq_drop, BB_BOCCUPY );
+  XorFile( sq_drop, OCCUPIED_FILE );
+  XorDiag2( sq_drop, OCCUPIED_DIAG2 );
+  XorDiag1( sq_drop, OCCUPIED_DIAG1 );
+
+  return iret;
+}
+
+
+int
+is_mate_w_pawn_drop( tree_t * restrict ptree, int sq_drop )
+{
+  bitboard_t bb, bb_sum, bb_move;
+  int ibk, ito, ifrom, iret, idirec;
+
+  BBAnd( bb_sum, BB_BKNIGHT, abb_w_knight_attacks[sq_drop] );
+
+  BBAndOr( bb_sum, BB_BSILVER, abb_w_silver_attacks[sq_drop] );
+  BBAndOr( bb_sum, BB_BTGOLD,  abb_w_gold_attacks[sq_drop] );
+
+  AttackBishop( bb, sq_drop );
+  BBAndOr( bb_sum, BB_B_BH, bb );
+
+  AttackRook( bb, sq_drop );
+  BBAndOr( bb_sum, BB_B_RD, bb );
+
+  BBOr( bb, BB_BHORSE, BB_BDRAGON );
+  BBAndOr( bb_sum, bb, abb_king_attacks[sq_drop] );
+
+  while ( BBToU( bb_sum ) )
+    {
+      ifrom  = FirstOne( bb_sum );
+      Xor( ifrom, bb_sum );
+
+      if ( IsDiscoverBK( ifrom, sq_drop ) ) { continue; }
+      return 0;
+    }
+
+  ibk  = SQ_BKING;
+  iret = 1;
+  Xor( sq_drop, BB_WOCCUPY );
+  XorFile( sq_drop, OCCUPIED_FILE );
+  XorDiag2( sq_drop, OCCUPIED_DIAG2 );
+  XorDiag1( sq_drop, OCCUPIED_DIAG1 );
+  
+  BBNot( bb_move, BB_BOCCUPY );
+  BBAnd( bb_move, bb_move, abb_king_attacks[ibk] );
+  while ( BBToU( bb_move ) )
+    {
+      ito = FirstOne( bb_move );
+      if ( ! is_black_attacked( ptree, ito ) )
+       {
+         iret = 0;
+         break;
+       }
+      Xor( ito, bb_move );
+    }
+
+  Xor( sq_drop, BB_WOCCUPY );
+  XorFile( sq_drop, OCCUPIED_FILE );
+  XorDiag2( sq_drop, OCCUPIED_DIAG2 );
+  XorDiag1( sq_drop, OCCUPIED_DIAG1 );
+
+  return iret;
+}
+
+
+bitboard_t
+attacks_to_piece( const tree_t * restrict ptree, int sq )
+{
+  bitboard_t bb_ret, bb_attacks, bb;
+
+  BBIni( bb_ret );
+  if ( sq < rank9*nfile && BOARD[sq+nfile] == pawn )
+    {
+      bb_ret = abb_mask[sq+nfile];
+    }
+  if ( sq >= nfile && BOARD[sq-nfile] == -pawn )
+    {
+      BBOr( bb_ret, bb_ret, abb_mask[sq-nfile] );
+    }
+
+  BBAndOr( bb_ret, BB_BKNIGHT, abb_w_knight_attacks[sq] );
+  BBAndOr( bb_ret, BB_WKNIGHT, abb_b_knight_attacks[sq] );
+
+  BBAndOr( bb_ret, BB_BSILVER, abb_w_silver_attacks[sq] );
+  BBAndOr( bb_ret, BB_WSILVER, abb_b_silver_attacks[sq] );
+
+  BBAndOr( bb_ret, BB_BTGOLD,  abb_w_gold_attacks[sq] );
+  BBAndOr( bb_ret, BB_WTGOLD,  abb_b_gold_attacks[sq] );
+
+  BBOr( bb, BB_B_HDK, BB_W_HDK );
+  BBAndOr( bb_ret, bb, abb_king_attacks[sq] );
+
+  BBOr( bb, BB_B_BH, BB_W_BH );
+  AttackBishop( bb_attacks, sq );
+  BBAndOr( bb_ret, bb, bb_attacks );
+
+  BBOr( bb, BB_B_RD, BB_W_RD );
+  bb_ret.p[aslide[sq].ir0]
+    |= bb.p[aslide[sq].ir0] & AttackRank( sq );
+  
+  BBAndOr( bb, BB_BLANCE, abb_plus_rays[sq] );
+  BBAndOr( bb, BB_WLANCE, abb_minus_rays[sq] );
+  bb_attacks = AttackFile( sq );
+  BBAndOr( bb_ret, bb, bb_attacks );
+  
+  return bb_ret;
+}
+
+
+unsigned int
+is_white_attacked( const tree_t * restrict ptree, int sq )
+{
+  bitboard_t bb;
+  unsigned int u;
+
+  u  = BBContract( BB_BPAWN_ATK, abb_mask[sq] );
+  u |= BBContract( BB_BKNIGHT,   abb_w_knight_attacks[sq] );
+  u |= BBContract( BB_BSILVER,   abb_w_silver_attacks[sq] );
+  u |= BBContract( BB_BTGOLD,    abb_w_gold_attacks[sq] );
+  u |= BBContract( BB_B_HDK,     abb_king_attacks[sq] );
+
+  AttackBishop( bb, sq );
+  u |= BBContract( BB_B_BH, bb );
+
+  u |= BB_B_RD.p[aslide[sq].ir0] & AttackRank( sq );
+
+  bb = AttackFile( sq );
+  u |= ( ( BB_BLANCE.p[0] & abb_plus_rays[sq].p[0] )
+        | BB_B_RD.p[0] ) & bb.p[0];
+  u |= ( ( BB_BLANCE.p[1] & abb_plus_rays[sq].p[1] )
+              | BB_B_RD.p[1] ) & bb.p[1];
+  u |= ( ( BB_BLANCE.p[2] & abb_plus_rays[sq].p[2] )
+              | BB_B_RD.p[2] ) & bb.p[2];
+
+  return u;
+}
+
+
+unsigned int
+is_black_attacked( const tree_t * restrict ptree, int sq )
+{
+  bitboard_t bb;
+  unsigned int u;
+
+  u  = BBContract( BB_WPAWN_ATK, abb_mask[sq] );
+  u |= BBContract( BB_WKNIGHT,   abb_b_knight_attacks[sq] );
+  u |= BBContract( BB_WSILVER,   abb_b_silver_attacks[sq] );
+  u |= BBContract( BB_WTGOLD,    abb_b_gold_attacks[sq] );
+  u |= BBContract( BB_W_HDK,     abb_king_attacks[sq] );
+
+  AttackBishop( bb, sq );
+  u |= BBContract( BB_W_BH, bb );
+
+  u |= BB_W_RD.p[aslide[sq].ir0] & AttackRank( sq );
+
+  bb = AttackFile( sq );
+  u |= ( ( BB_WLANCE.p[0] & abb_minus_rays[sq].p[0] )
+        | BB_W_RD.p[0] ) & bb.p[0];
+  u |= ( ( BB_WLANCE.p[1] & abb_minus_rays[sq].p[1] )
+              | BB_W_RD.p[1] ) & bb.p[1];
+  u |= ( ( BB_WLANCE.p[2] & abb_minus_rays[sq].p[2] )
+              | BB_W_RD.p[2] ) & bb.p[2];
+
+  return u;
+}
diff --git a/bitop.c b/bitop.c
new file mode 100644 (file)
index 0000000..13fbe58
--- /dev/null
+++ b/bitop.c
@@ -0,0 +1,304 @@
+#include "shogi.h"
+
+int
+popu_count012( unsigned int u0, unsigned int u1, unsigned int u2 )
+{
+  int counter = 0;
+  while ( u0 ) { counter++;  u0 &= u0 - 1U; }
+  while ( u1 ) { counter++;  u1 &= u1 - 1U; }
+  while ( u2 ) { counter++;  u2 &= u2 - 1U; }
+  return counter;
+}
+
+
+#if defined(_MSC_VER)
+
+int
+first_one012( unsigned int u0, unsigned int u1, unsigned int u2 )
+{
+  unsigned long index;
+
+  if ( _BitScanReverse( &index, u0 ) ) { return 26 - index; }
+  if ( _BitScanReverse( &index, u1 ) ) { return 53 - index; }
+  _BitScanReverse( &index, u2 );
+  return 80 - index;
+}
+
+int
+last_one210( unsigned int u2, unsigned int u1, unsigned int u0 )
+{
+  unsigned long index;
+
+  if ( _BitScanForward( &index, u2 ) ) { return 80 - index; }
+  if ( _BitScanForward( &index, u1 ) ) { return 53 - index; }
+  _BitScanForward( &index, u0 );
+  return 26 - index;
+}
+
+int
+first_one01( unsigned int u0, unsigned int u1 )
+{
+  unsigned long index;
+
+  if ( _BitScanReverse( &index, u0 ) ) { return 26 - index; }
+  _BitScanReverse( &index, u1 );
+  return 53 - index;
+}
+
+int
+first_one12( unsigned int u1, unsigned int u2 )
+{
+  unsigned long index;
+  
+  if ( _BitScanReverse( &index, u1 ) ) { return 53 - index; }
+  _BitScanReverse( &index, u2 );
+  return 80 - index;
+}
+
+int
+last_one01( unsigned int u0, unsigned int u1 )
+{
+  unsigned long index;
+
+  if ( _BitScanForward( &index, u1 ) ) { return 53 - index; }
+  _BitScanForward( &index, u0 );
+  return 26 - index;
+}
+
+int
+last_one12( unsigned int u1, unsigned u2 )
+{
+  unsigned long index;
+
+  if ( _BitScanForward( &index, u2 ) ) { return 80 - index; }
+  _BitScanForward( &index, u1 );
+  return 53 - index;
+}
+
+int
+first_one1( unsigned int u1 )
+{
+  unsigned long index;
+  
+  _BitScanReverse( &index, u1 );
+  return 53 - index;
+}
+
+int
+first_one2( unsigned int u2 )
+{
+  unsigned long index;
+  
+  _BitScanReverse( &index, u2 );
+  return 80 - index;
+}
+
+int
+last_one0( unsigned int u0 )
+{
+  unsigned long index;
+  
+  _BitScanForward( &index, u0 );
+  return 26 - index;
+}
+
+int
+last_one1( unsigned int u1 )
+{
+  unsigned long index;
+  
+  _BitScanForward( &index, u1 );
+  return 53 - index;
+}
+
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+
+int
+first_one012( unsigned int u0, unsigned int u1, unsigned int u2 )
+{
+  if ( u0 ) { return __builtin_clz( u0 ) - 5; }
+  if ( u1 ) { return __builtin_clz( u1 ) + 22; }
+  return __builtin_clz( u2 ) + 49;
+}
+
+
+int
+last_one210( unsigned int u2, unsigned int u1, unsigned int u0 )
+{
+  if ( u2 ) { return 80 - __builtin_ctz( u2 ); }
+  if ( u1 ) { return 53 - __builtin_ctz( u1 ); }
+  return 26 - __builtin_ctz( u0 );
+}
+
+
+int
+first_one01( unsigned int u0, unsigned int u1 )
+{
+  if ( u0 ) { return __builtin_clz( u0 ) - 5; }
+  return __builtin_clz( u1 ) + 22;
+}
+
+
+int
+first_one12( unsigned int u1, unsigned int u2 )
+{
+  if ( u1 ) { return __builtin_clz( u1 ) + 22; }
+  return __builtin_clz( u2 ) + 49;
+}
+
+
+int
+last_one01( unsigned int u0, unsigned int u1 )
+{
+  if ( u1 ) { return 53 - __builtin_ctz( u1 ); }
+  return 26 - __builtin_ctz( u0 );
+}
+
+
+int
+last_one12( unsigned int u1, unsigned int u2 )
+{
+  if ( u2 ) { return 80 - __builtin_ctz( u2 ); }
+  return 53 - __builtin_ctz( u1 );
+}
+
+
+int first_one1( unsigned int u1 ) { return __builtin_clz( u1 ) + 22; }
+int first_one2( unsigned int u2 ) { return __builtin_clz( u2 ) + 49; }
+int last_one0( unsigned int u0 ) { return 26 - __builtin_ctz( u0 ); }
+int last_one1( unsigned int u1 ) { return 53 - __builtin_ctz( u1 ); }
+
+#else
+
+int
+first_one012( unsigned int u0, unsigned int u1, unsigned int u2 )
+{
+  if ( u0 & 0x7fc0000 ) { return aifirst_one[u0>>18] +  0; }
+  if ( u0 & 0x7fffe00 ) { return aifirst_one[u0>> 9] +  9; }
+  if ( u0 & 0x7ffffff ) { return aifirst_one[u0    ] + 18; }
+
+  if ( u1 & 0x7fc0000 ) { return aifirst_one[u1>>18] + 27; }
+  if ( u1 & 0x7fffe00 ) { return aifirst_one[u1>> 9] + 36; }
+  if ( u1 & 0x7ffffff ) { return aifirst_one[u1    ] + 45; }
+
+  if ( u2 & 0x7fc0000 ) { return aifirst_one[u2>>18] + 54; }
+  if ( u2 & 0x7fffe00 ) { return aifirst_one[u2>> 9] + 63; }
+  return aifirst_one[u2] + 72;
+}
+
+
+int
+last_one210( unsigned int u2, unsigned int u1, unsigned int u0 )
+{
+  unsigned int j;
+
+  j = u2 & 0x00001ff;  if ( j ) { return ailast_one[j    ] + 72; }
+  j = u2 & 0x003ffff;  if ( j ) { return ailast_one[j>> 9] + 63; }
+  if ( u2 & 0x7ffffff ) { return ailast_one[u2>>18] + 54; }
+
+  j = u1 & 0x00001ff;  if ( j ) { return ailast_one[j    ] + 45; }
+  j = u1 & 0x003ffff;  if ( j ) { return ailast_one[j>> 9] + 36; }
+  if ( u1 & 0x7ffffff ) { return ailast_one[u1>>18] + 27; }
+
+  j = u0 & 0x00001ff;  if ( j ) { return ailast_one[j    ] + 18; }
+  j = u0 & 0x003ffff;  if ( j ) { return ailast_one[j>> 9] +  9; }
+  return ailast_one[u0>>18];
+}
+
+
+int
+first_one01( unsigned int u0, unsigned int u1 )
+{
+  if ( u0 & 0x7fc0000 ) { return aifirst_one[u0>>18] +  0; }
+  if ( u0 & 0x7fffe00 ) { return aifirst_one[u0>> 9] +  9; }
+  if ( u0 & 0x7ffffff ) { return aifirst_one[u0    ] + 18; }
+
+  if ( u1 & 0x7fc0000 ) { return aifirst_one[u1>>18] + 27; }
+  if ( u1 & 0x7fffe00 ) { return aifirst_one[u1>> 9] + 36; }
+  return aifirst_one[ u1 ] + 45;
+}
+
+
+int
+first_one12( unsigned int u1, unsigned int u2 )
+{
+  if ( u1 & 0x7fc0000 ) { return aifirst_one[u1>>18] + 27; }
+  if ( u1 & 0x7fffe00 ) { return aifirst_one[u1>> 9] + 36; }
+  if ( u1 & 0x7ffffff ) { return aifirst_one[u1    ] + 45; }
+
+  if ( u2 & 0x7fc0000 ) { return aifirst_one[u2>>18] + 54; }
+  if ( u2 & 0x7fffe00 ) { return aifirst_one[u2>> 9] + 63; }
+  return aifirst_one[ u2 ] + 72;
+}
+
+
+int
+last_one01( unsigned int u0, unsigned int u1 )
+{
+  unsigned int j;
+
+  j = u1 & 0x00001ff;  if ( j ) { return ailast_one[j    ] + 45; }
+  j = u1 & 0x003ffff;  if ( j ) { return ailast_one[j>> 9] + 36; }
+  if ( u1 & 0x7ffffff ) { return ailast_one[u1>>18] + 27; }
+
+  j = u0 & 0x00001ff;  if ( j ) { return ailast_one[j    ] + 18; }
+  j = u0 & 0x003ffff;  if ( j ) { return ailast_one[j>> 9] +  9; }
+  return ailast_one[u0>>18];
+}
+
+
+int
+last_one12( unsigned int u1, unsigned int u2 )
+{
+  unsigned int j;
+
+  j = u2 & 0x00001ff;  if ( j ) { return ailast_one[j    ] + 72; }
+  j = u2 & 0x003ffff;  if ( j ) { return ailast_one[j>> 9] + 63; }
+  if ( u2 & 0x7ffffff ) { return ailast_one[u2>>18] + 54; }
+
+  j = u1 & 0x00001ff;  if ( j ) { return ailast_one[j    ] + 45; }
+  j = u1 & 0x003ffff;  if ( j ) { return ailast_one[j>> 9] + 36; }
+  return ailast_one[u1>>18] + 27;
+}
+
+
+int
+first_one1( unsigned int u1 )
+{
+  if ( u1 & 0x7fc0000U ) { return aifirst_one[u1>>18] + 27; }
+  if ( u1 & 0x7fffe00U ) { return aifirst_one[u1>> 9] + 36; }
+  return aifirst_one[u1] + 45;
+}
+
+
+int
+first_one2( unsigned int u2 )
+{
+  if ( u2 & 0x7fc0000U ) { return aifirst_one[u2>>18] + 54; }
+  if ( u2 & 0x7fffe00U ) { return aifirst_one[u2>> 9] + 63; }
+  return aifirst_one[u2] + 72;
+}
+
+
+int
+last_one0( unsigned int i )
+{
+  unsigned int j;
+
+  j = i & 0x00001ffU;  if ( j ) { return ailast_one[j    ] + 18; }
+  j = i & 0x003ffffU;  if ( j ) { return ailast_one[j>> 9] +  9; }
+  return ailast_one[i>>18];
+}
+
+
+int
+last_one1( unsigned int u1 )
+{
+  unsigned int j;
+
+  j = u1 & 0x00001ffU;  if ( j ) { return ailast_one[j    ] + 45; }
+  j = u1 & 0x003ffffU;  if ( j ) { return ailast_one[j>> 9] + 36; }
+  return ailast_one[u1>>18] + 27;
+}
+
+#endif
diff --git a/bonanza.ico b/bonanza.ico
new file mode 100644 (file)
index 0000000..fc71e77
Binary files /dev/null and b/bonanza.ico differ
diff --git a/bonanza.rc b/bonanza.rc
new file mode 100644 (file)
index 0000000..27739b1
--- /dev/null
@@ -0,0 +1 @@
+"icon" ICON "bonanza.ico"\r
diff --git a/book.c b/book.c
new file mode 100644 (file)
index 0000000..e8336e6
--- /dev/null
+++ b/book.c
@@ -0,0 +1,1230 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include "shogi.h"
+
+/*
+  Opening Book Data Structure: Index BookData
+
+    Index:         IndexEntry.. (NUM_SECTION times)
+
+      IndexEntry:  SectionPointer SectionSize
+
+    BookData:      Section.. (NUM_SECTION times)
+
+      Section:     [DataEntry]..
+
+        DataEntry: Header Move...
+
+
+- SectionPointer
+  4 byte:  position of the section in character
+
+- SectionSize
+  2 byte:  size of the section in character
+- Header
+  1 byte:  number of bytes for the DataEntry
+  8 byte:  hash key
+  
+- Move
+  2 byte:  a book move
+  2 byte:  frequency
+ */
+
+#define BK_SIZE_INDEX     6
+#define BK_SIZE_HEADER    9
+#define BK_SIZE_MOVE      4
+#define BK_MAX_MOVE       32
+
+#if ( BK_SIZE_HEADER + BK_SIZE_MOVE * BK_MAX_MOVE > UCHAR_MAX )
+#  error "Maximum size of DataEntry is larger than UCHAR_MAX"
+#endif
+
+typedef struct { unsigned short smove, freq; } book_move_t;
+
+typedef struct { int from, to; } ft_t;
+
+static int book_read( uint64_t key, book_move_t *pbook_move,
+                     unsigned int *pposition );
+static uint64_t book_hash_func( const tree_t * restrict ptree,int *pis_flip );
+static unsigned int bm2move( const tree_t * restrict ptree, unsigned int bmove,
+                            int is_flip );
+static ft_t flip_ft( ft_t ft, int turn, int is_flip );
+static int normalize_book_move( book_move_t * restrict pbook_move, int moves );
+
+
+int
+book_on( void )
+{
+  int iret = file_close( pf_book );
+  if ( iret < 0 ) { return iret; }
+
+  pf_book = file_open( str_book, "rb+" );
+  if ( pf_book == NULL ) { return -2; }
+
+  return 1;
+}
+
+
+int
+book_off( void )
+{
+  int iret = file_close( pf_book );
+  if ( iret < 0 ) { return iret; }
+
+  pf_book = NULL;
+
+  return 1;
+}
+
+
+int
+book_probe( tree_t * restrict ptree )
+{
+  book_move_t abook_move[ BK_MAX_MOVE+1 ];
+  uint64_t key;
+  double dscore, drand;
+  unsigned int move, position, freq_lower_limit;
+  int is_flip, i, j, moves, ply;
+
+  key   = book_hash_func( ptree, &is_flip );
+
+  moves = book_read( key, abook_move, &position );
+  if ( moves <= 0 ) { return moves; }
+
+#if ! defined(MINIMUM) || ! defined(NDEBUG)
+  for ( j = i = 0; i < moves; i++ ) { j += abook_move[i].freq; }
+  if ( j != USHRT_MAX )
+    {
+      str_error = "normalization error (book.bin)";
+      return -1;
+    }
+#endif
+
+  /* decision of book move based on pseudo-random number */
+  if ( game_status & flag_puzzling ) { j = 0; }
+  else {
+    drand = (double)rand64() / (double)UINT64_MAX;
+
+    if ( game_status & flag_narrow_book )
+      {
+#if defined(BK_ULTRA_NARROW)
+       freq_lower_limit = abook_move[0].freq;
+#else
+       freq_lower_limit = abook_move[0].freq / 2U;
+#endif
+
+       for ( i = 1; i < moves; i++ )
+         {
+           if ( abook_move[i].freq < freq_lower_limit ) { break; }
+         }
+       moves = i;
+       normalize_book_move( abook_move, moves );
+      }
+
+    for ( j = moves-1; j > 0; j-- )
+      {
+       dscore = (double)( abook_move[j].freq ) / (double)USHRT_MAX;
+       if ( drand <= dscore ) { break; }
+       drand -= dscore;
+      }
+    if ( ! abook_move[j].freq ) { j = 0; }
+  }
+
+  /* show results */
+  if ( ! ( game_status & ( flag_pondering | flag_puzzling ) ) )
+    {
+      Out( "    move     freq\n" );
+      OutCsaShogi( "info" );
+      for ( i = 0; i < moves; i++ )
+       {
+         const char *str;
+         
+         dscore = (double)abook_move[i].freq / (double)USHRT_MAX;
+         move = bm2move( ptree, (unsigned int)abook_move[i].smove, is_flip );
+         str  = str_CSA_move( move );
+         
+         Out( "  %c %s  %5.1f\n", i == j ? '*' : ' ', str, dscore * 100.0 );
+         OutCsaShogi( " %s(%.0f%%)", str, dscore * 100.0 );
+       }
+      OutCsaShogi( "\n" );
+    }
+
+  move = bm2move( ptree, (unsigned int)abook_move[j].smove, is_flip );
+  if ( ! is_move_valid( ptree, move, root_turn ) )
+    {
+      out_warning( "BAD BOOK MOVE!! " );
+      return 0;
+    }
+
+  ply = record_game.moves;
+  if ( game_status & flag_pondering ) { ply++; }
+  if ( ply < HASH_REG_HIST_LEN )
+    {
+      history_book_learn[ ply ].key_book    = key;  
+      history_book_learn[ ply ].move_probed = move;
+      history_book_learn[ ply ].key_probed  = (unsigned int)HASH_KEY;  
+      history_book_learn[ ply ].hand_probed = HAND_B;
+      history_book_learn[ ply ].data        = (unsigned int)is_flip << 30;
+      if ( game_status & flag_narrow_book )
+       {
+         history_book_learn[ ply ].data |= 1U << 29;
+       }
+    }
+
+  ptree->current_move[1] = move;
+
+  return 1;
+}
+
+
+static int
+book_read( uint64_t key, book_move_t *pbook_move, unsigned int *pposition )
+{
+  uint64_t book_key;
+  const unsigned char *p;
+  unsigned int position, size_section, size, u;
+  int ibook_section, moves;
+  unsigned short s;
+
+  ibook_section = (int)( (unsigned int)key & (unsigned int)( NUM_SECTION-1 ) );
+
+  if ( fseek( pf_book, BK_SIZE_INDEX*ibook_section, SEEK_SET ) == EOF )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  
+  if ( fread( &position, sizeof(int), 1, pf_book ) != 1 )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  
+  if ( fread( &s, sizeof(unsigned short), 1, pf_book ) != 1 )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  size_section = (unsigned int)s;
+  if ( size_section > MAX_SIZE_SECTION )
+    {
+      str_error = str_book_error;
+      return -2;
+    }
+
+  if ( fseek( pf_book, (long)position, SEEK_SET ) == EOF )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  if ( fread( book_section, sizeof(unsigned char), (size_t)size_section,
+             pf_book ) != (size_t)size_section )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  
+  size       = 0;
+  p          = book_section;
+  *pposition = position;
+  while ( book_section + size_section > p )
+    {
+      size     = (unsigned int)p[0];
+      book_key = *(uint64_t *)( p + 1 );
+      if ( book_key == key ) { break; }
+      p          += size;
+      *pposition += size;
+    }
+  if ( book_section + size_section <= p ) { return 0; }
+
+  for ( moves = 0, u = BK_SIZE_HEADER; u < size; moves++, u += BK_SIZE_MOVE )
+    {
+      pbook_move[moves].smove  = *(unsigned short *)(p+u+0);
+      pbook_move[moves].freq   = *(unsigned short *)(p+u+2);
+    }
+
+  return moves;
+}
+
+
+static ft_t
+flip_ft( ft_t ft, int turn, int is_flip )
+{
+  int ito_rank, ito_file, ifrom_rank, ifrom_file;
+
+  ito_rank = airank[ft.to];
+  ito_file = aifile[ft.to];
+  if ( ft.from < nsquare )
+    {
+      ifrom_rank = airank[ft.from];
+      ifrom_file = aifile[ft.from];
+    }
+  else { ifrom_rank = ifrom_file = 0; }
+
+  if ( turn )
+    {
+      ito_rank = rank9 - ito_rank;
+      ito_file = file9 - ito_file;
+      if ( ft.from < nsquare )
+       {
+         ifrom_rank = rank9 - ifrom_rank;
+         ifrom_file = file9 - ifrom_file;
+       }
+    }
+
+  if ( is_flip )
+    {
+      ito_file = file9 - ito_file;
+      if ( ft.from < nsquare ) { ifrom_file = file9 - ifrom_file; }
+    }
+
+  ft.to = ito_rank * nfile + ito_file;
+  if ( ft.from < nsquare ) { ft.from = ifrom_rank * nfile + ifrom_file; }
+
+  return ft;
+}
+
+
+static unsigned int
+bm2move( const tree_t * restrict ptree, unsigned int bmove, int is_flip )
+{
+  ft_t ft;
+  unsigned int move;
+  int is_promote;
+
+  ft.to      = I2To(bmove);
+  ft.from    = I2From(bmove);
+  ft         = flip_ft( ft, root_turn, is_flip );
+  is_promote = I2IsPromote(bmove);
+
+  move  = (unsigned int)( is_promote | From2Move(ft.from) | ft.to );
+  if ( ft.from >= nsquare ) { return move; }
+
+  if ( root_turn )
+    {
+      move |= Cap2Move(BOARD[ft.to]);
+      move |= Piece2Move(-BOARD[ft.from]);
+    }
+  else {
+    move |= Cap2Move(-BOARD[ft.to]);
+    move |= Piece2Move(BOARD[ft.from]);
+  }
+
+  return move;
+}
+
+
+static uint64_t
+book_hash_func( const tree_t * restrict ptree, int *pis_flip )
+{
+  uint64_t key, key_flip;
+  unsigned int hand;
+  int i, iflip, irank, ifile, piece;
+
+  key = 0;
+  hand = root_turn ? HAND_W : HAND_B;
+  i = I2HandPawn(hand);    if ( i ) { key ^= b_hand_pawn_rand[i-1]; }
+  i = I2HandLance(hand);   if ( i ) { key ^= b_hand_lance_rand[i-1]; }
+  i = I2HandKnight(hand);  if ( i ) { key ^= b_hand_knight_rand[i-1]; }
+  i = I2HandSilver(hand);  if ( i ) { key ^= b_hand_silver_rand[i-1]; }
+  i = I2HandGold(hand);    if ( i ) { key ^= b_hand_gold_rand[i-1]; }
+  i = I2HandBishop(hand);  if ( i ) { key ^= b_hand_bishop_rand[i-1]; }
+  i = I2HandRook(hand);    if ( i ) { key ^= b_hand_rook_rand[i-1]; }
+
+  hand = root_turn ? HAND_B : HAND_W;
+  i = I2HandPawn(hand);    if ( i ) { key ^= w_hand_pawn_rand[i-1]; }
+  i = I2HandLance(hand);   if ( i ) { key ^= w_hand_lance_rand[i-1]; }
+  i = I2HandKnight(hand);  if ( i ) { key ^= w_hand_knight_rand[i-1]; }
+  i = I2HandSilver(hand);  if ( i ) { key ^= w_hand_silver_rand[i-1]; }
+  i = I2HandGold(hand);    if ( i ) { key ^= w_hand_gold_rand[i-1]; }
+  i = I2HandBishop(hand);  if ( i ) { key ^= w_hand_bishop_rand[i-1]; }
+  i = I2HandRook(hand);    if ( i ) { key ^= w_hand_rook_rand[i-1]; }
+
+  key_flip = key;
+
+  for ( irank = rank1; irank <= rank9; irank++ )
+    for ( ifile = file1; ifile <= file9; ifile++ )
+      {
+       if ( root_turn )
+         {
+           i     = ( rank9 - irank ) * nfile + file9 - ifile;
+           iflip = ( rank9 - irank ) * nfile + ifile;
+           piece = -(int)BOARD[nsquare-i-1];
+         }
+       else {
+         i     = irank * nfile + ifile;
+         iflip = irank * nfile + file9 - ifile;
+         piece = (int)BOARD[i];
+       }
+
+#define Foo(t_pc)  key      ^= (t_pc ## _rand)[i];     \
+                   key_flip ^= (t_pc ## _rand)[iflip];
+       switch ( piece )
+         {
+         case  pawn:        Foo( b_pawn );        break;
+         case  lance:       Foo( b_lance );       break;
+         case  knight:      Foo( b_knight );      break;
+         case  silver:      Foo( b_silver );      break;
+         case  gold:        Foo( b_gold );        break;
+         case  bishop:      Foo( b_bishop );      break;
+         case  rook:        Foo( b_rook );        break;
+         case  king:        Foo( b_king );        break;
+         case  pro_pawn:    Foo( b_pro_pawn );    break;
+         case  pro_lance:   Foo( b_pro_lance );   break;
+         case  pro_knight:  Foo( b_pro_knight );  break;
+         case  pro_silver:  Foo( b_pro_silver );  break;
+         case  horse:       Foo( b_horse );       break;
+         case  dragon:      Foo( b_dragon );      break;
+         case -pawn:        Foo( w_pawn );        break;
+         case -lance:       Foo( w_lance );       break;
+         case -knight:      Foo( w_knight );      break;
+         case -silver:      Foo( w_silver );      break;
+         case -gold:        Foo( w_gold );        break;
+         case -bishop:      Foo( w_bishop );      break;
+         case -rook:        Foo( w_rook );        break;
+         case -king:        Foo( w_king );        break;
+         case -pro_pawn:    Foo( w_pro_pawn );    break;
+         case -pro_lance:   Foo( w_pro_lance );   break;
+         case -pro_knight:  Foo( w_pro_knight );  break;
+         case -pro_silver:  Foo( w_pro_silver );  break;
+         case -horse:       Foo( w_horse );       break;
+         case -dragon:      Foo( w_dragon );      break;
+         }
+#undef Foo
+      }
+
+  if ( key > key_flip )
+    {
+      key       = key_flip;
+      *pis_flip = 1;
+    }
+  else { *pis_flip = 0; }
+
+  return key;
+}
+
+
+static int
+normalize_book_move( book_move_t * restrict pbook_move, int moves )
+{
+  book_move_t swap;
+  double dscale;
+  unsigned int u, norm;
+  int i, j;
+
+  /* insertion sort by nwin */
+  pbook_move[moves].freq = 0;
+  for ( i = moves-2; i >= 0; i-- )
+    {
+      u    = pbook_move[i].freq;
+      swap = pbook_move[i];
+      for ( j = i+1; pbook_move[j].freq > u; j++ )
+       {
+         pbook_move[j-1] = pbook_move[j];
+       }
+      pbook_move[j-1] = swap;
+    }
+      
+  /* normalization */
+  for ( norm = 0, i = 0; i < moves; i++ ) { norm += pbook_move[i].freq; }
+  dscale = (double)USHRT_MAX / (double)norm;
+  for ( norm = 0, i = 0; i < moves; i++ )
+    {
+      u = (unsigned int)( (double)pbook_move[i].freq * dscale );
+      if ( ! u )           { u = 1U; }
+      if ( u > USHRT_MAX ) { u = USHRT_MAX; }
+      
+      pbook_move[i].freq = (unsigned short)u;
+      norm              += u;
+    }
+  if ( norm > (unsigned int)pbook_move[0].freq + USHRT_MAX )
+    {
+      str_error = "normalization error";
+      return -2;
+    }
+
+  pbook_move[0].freq
+    = (unsigned short)( pbook_move[0].freq + USHRT_MAX - norm );
+  
+  return 1;
+}
+
+
+#if ! defined(MINIMUM)
+
+#define MaxNumCell      0x400000
+#if defined(BK_SMALL)
+#  define MaxPlyBook    64
+#else
+#  define MaxPlyBook    128
+#endif
+
+typedef struct {
+  unsigned int nwin, ngame, nwin_bnz, ngame_bnz, move;
+} record_move_t;
+
+typedef struct {
+  uint64_t key;
+  unsigned short smove;
+  unsigned char result;
+} cell_t;
+
+static unsigned int move2bm( unsigned int move, int turn, int is_flip );
+static int find_min_cell( const cell_t *pcell, int ntemp );
+static int read_a_cell( cell_t *pcell, FILE *pf );
+static int CONV_CDECL compare( const void * p1, const void *p2 );
+static int dump_cell( cell_t *pcell, int ncell, int num_tmpfile );
+static int examine_game( tree_t * restrict ptree, record_t *pr,
+                        int *presult, unsigned int *pmoves );
+static int move_selection( const record_move_t *p, int ngame, int nwin );
+static int make_cell_csa( tree_t * restrict ptree, record_t *pr,
+                         cell_t *pcell, int num_tmpfile );
+static int merge_cell( record_move_t *precord_move, FILE **ppf,
+                      int num_tmpfile );
+static int read_anti_book( tree_t * restrict ptree, record_t * pr );
+
+int
+book_create( tree_t * restrict ptree )
+{
+  record_t record;
+  FILE *ppf[101];
+  char str_filename[SIZE_FILENAME];
+  record_move_t *precord_move;
+  cell_t *pcell;
+  int iret, num_tmpfile, i, j;
+
+
+  num_tmpfile = 0;
+
+  pcell = memory_alloc( sizeof(cell_t) * MaxNumCell );
+  if ( pcell == NULL ) { return -2; }
+
+  Out("\n  [book.csa]\n");
+  
+  iret = record_open( &record, "book.csa", mode_read, NULL, NULL );
+  if ( iret < 0 ) { return iret; }
+
+  num_tmpfile = make_cell_csa( ptree, &record, pcell, num_tmpfile );
+  if ( num_tmpfile < 0 )
+    {
+      memory_free( pcell );
+      record_close( &record );
+      return num_tmpfile;
+    }
+
+  iret = record_close( &record );
+  if ( iret < 0 )
+    {
+      memory_free( pcell );
+      return iret;
+    }
+
+  memory_free( pcell );
+
+  if ( ! num_tmpfile )
+    {
+      str_error = "No book data";
+      return -2;
+    }
+
+  if ( num_tmpfile > 100 )
+    {
+      str_error = "Number of tmp??.bin files are too large.";
+      return -2;
+    }
+
+  iret = book_off();
+  if ( iret < 0 ) { return iret; }
+
+  pf_book = file_open( str_book, "wb" );
+  if ( pf_book == NULL ) { return -2; }
+
+  precord_move = memory_alloc( sizeof(record_move_t) * (MAX_LEGAL_MOVES+1) );
+  if ( precord_move == NULL ) { return -2; }
+  
+  for ( i = 0; i < num_tmpfile; i++ )
+    {
+      snprintf( str_filename, SIZE_FILENAME, "tmp%02d.bin", i );
+      ppf[i] = file_open( str_filename, "rb" );
+      if ( ppf[i] == NULL )
+       {
+         memory_free( precord_move );
+         file_close( pf_book );
+         for ( j = 0; j < i; j++ ) { file_close( ppf[j] ); }
+         return -2;
+       }
+    }
+
+  iret = merge_cell( precord_move, ppf, num_tmpfile );
+  if ( iret < 0 )
+    {
+      memory_free( precord_move );
+      file_close( pf_book );
+      for ( i = 0; i < num_tmpfile; i++ ) { file_close( ppf[i] ); }
+      return iret;
+    }
+
+  memory_free( precord_move );
+
+  iret = book_on();
+  if ( iret < 0 ) { return iret; }
+
+#if 1
+  iret = record_open( &record, "book_anti.csa", mode_read, NULL, NULL );
+  if ( iret < 0 ) { return iret; }
+
+  iret = read_anti_book( ptree, &record );
+  if ( iret < 0 )
+    {
+      record_close( &record );
+      return iret;
+    }
+#endif
+
+  return record_close( &record );
+}
+
+
+static int
+read_anti_book( tree_t * restrict ptree, record_t * pr )
+{
+  uint64_t key;
+  book_move_t abook_move[ BK_MAX_MOVE+1 ];
+  size_t size;
+  unsigned int move, position, bm, umoves;
+  int iret, result, istatus, is_flip, i, moves;
+
+  do {
+
+    istatus = examine_game( ptree, pr, &result, &umoves );
+    if ( istatus < 0 ) { return istatus; }
+    if ( result == -2 )
+      {
+       str_error = "no result in book_anti.csa";
+       return -2;
+      }
+
+    while ( pr->moves < umoves-1U )
+      {
+       istatus = in_CSA( ptree, pr, NULL, 0 );
+       if ( istatus != record_misc )
+         {
+           str_error = "internal error at book.c";
+           return -2;
+         }
+      }
+
+    istatus = in_CSA( ptree, pr, &move, flag_nomake_move );
+    if ( istatus < 0 ) { return istatus; }
+
+    key = book_hash_func( ptree, &is_flip );
+    
+    moves = book_read( key, abook_move, &position );
+    if ( moves < 0 ) { return moves; }
+
+    bm = move2bm( move, root_turn, is_flip );
+    for ( i = 0; i < moves; i++ )
+      {
+       if ( bm == abook_move[i].smove ) { break; }
+      }
+
+    if ( i == moves )
+      {
+       out_board( ptree, stdout, 0, 0 );
+       printf( "%s is not found in the book\n\n", str_CSA_move(move) );
+      }
+    else {
+      abook_move[i].freq = 0;
+
+      iret = normalize_book_move( abook_move, moves );
+      if ( iret < 0 ) { return iret; }
+
+      for ( i = 0; i < moves; i++ )
+       {
+         *(unsigned short *)( book_section + i*BK_SIZE_MOVE )
+           = abook_move[i].smove;
+         *(unsigned short *)( book_section + i*BK_SIZE_MOVE + 2 )
+           = abook_move[i].freq;
+       }
+      size = (size_t)( moves * BK_SIZE_MOVE );
+      if ( fseek( pf_book, (long)(position+BK_SIZE_HEADER), SEEK_SET ) == EOF
+          || fwrite( book_section, sizeof(unsigned char),
+                     size, pf_book ) != size )
+       {
+         str_error = str_io_error;
+         return -2;
+       }
+      
+      out_board( ptree, stdout, 0, 0 );
+      printf( "%s is discarded\n\n", str_CSA_move(move) );
+    }
+
+    if ( istatus != record_eof && istatus != record_next )
+      {
+       istatus = record_wind( pr );
+       if ( istatus < 0 ) { return istatus; }
+      }
+  } while ( istatus != record_eof );
+
+  return 1;
+}
+
+
+static int
+make_cell_csa( tree_t * restrict ptree, record_t *pr, cell_t *pcell,
+              int num_tmpfile )
+{
+  struct {
+    uint64_t hash_key;
+    unsigned int hand, move;
+  } rep_tbl[MaxPlyBook+1];
+  uint64_t key;
+  unsigned int nwhite_win, nblack_win, ndraw, ninvalid, nbnz_black, nbnz_white;
+  unsigned int move, moves, uresult;
+  int icell, result, is_flip, iret, istatus, ply, i, black_bnz, white_bnz;
+
+  nwhite_win = nblack_win = ndraw = ninvalid = nbnz_white = nbnz_black = 0;
+  icell = black_bnz = white_bnz = 0;
+  istatus = record_next;
+
+  while ( istatus != record_eof ) {
+
+    istatus = examine_game( ptree, pr, &result, &moves );
+    if ( istatus < 0 ) { return istatus; }
+
+    if      ( result == -1 ) { nwhite_win++; }
+    else if ( result ==  1 ) { nblack_win++; }
+    else if ( result ==  0 ) { ndraw++; }
+    else {
+      ninvalid++;
+      continue;
+    }
+    
+    if ( moves > MaxPlyBook ) { moves = MaxPlyBook; }
+
+    for ( ply = 0;; ply++ ) {
+      istatus = in_CSA( ptree, pr, &move, flag_nomake_move );
+      if ( ! ply )
+       {
+         black_bnz = strcmp( pr->str_name1, "Bonanza" ) ? 0 : 1;
+         white_bnz = strcmp( pr->str_name2, "Bonanza" ) ? 0 : 1;
+         if ( ! strcmp( pr->str_name1, "Bonanza" ) )
+           {
+             black_bnz   = 1;
+             nbnz_black += 1;
+           }
+         else { black_bnz = 0; }
+         if ( ! strcmp( pr->str_name2, "Bonanza" ) )
+           {
+             white_bnz   = 1;
+             nbnz_white += 1;
+           }
+         else { white_bnz = 0; }
+       }
+      if ( istatus < 0 ) { return istatus; }
+      if ( istatus == record_resign && ! moves ) { break; }
+      if ( istatus != record_misc )
+       {
+         str_error = "internal error at book.c";
+         return -2;
+       }
+
+      rep_tbl[ply].hash_key = HASH_KEY;
+      rep_tbl[ply].hand     = HAND_B;
+      rep_tbl[ply].move     = move;
+      for ( i = ( ply & 1 ); i < ply; i += 2 )
+       {
+         if ( rep_tbl[i].hash_key == HASH_KEY
+              && rep_tbl[i].hand == HAND_B
+              && rep_tbl[i].move == move ) { break; }
+       }
+
+      if ( i == ply ) {
+       key     = book_hash_func( ptree, &is_flip );
+       uresult = (unsigned int)( root_turn ? -1*result+1 : result+1 );
+       if ( ( root_turn == black && black_bnz )
+            || ( root_turn == white && white_bnz ) ) { uresult |= 0x4U; }
+
+       pcell[icell].key    = key;
+       pcell[icell].result = (unsigned char)uresult;
+       pcell[icell].smove  = (unsigned short)move2bm( move, root_turn,
+                                                      is_flip );
+       icell++;
+       if ( icell == MaxNumCell ) {
+         iret = dump_cell( pcell, icell, num_tmpfile++ );
+         if ( iret < 0 ) { return iret; }
+         icell = 0;
+       }
+       if ( ! ( (icell-1) & 0x1ffff ) ) { Out( "." ); }
+      }
+      
+      if ( pr->moves >= moves ) { break; }
+
+      iret = make_move_root( ptree, move, 0 );
+      if ( iret < 0 ) {        return iret; }
+    }
+
+    if ( istatus != record_eof && istatus != record_next )
+      {
+       istatus = record_wind( pr );
+       if ( istatus < 0 ) { return istatus; }
+      }
+  }
+
+  iret  = dump_cell( pcell, icell, num_tmpfile++ );
+  if ( iret < 0 ) { return iret; }
+
+  Out( "\n"
+       "Total games:   %7u\n"
+       "  Discarded:   %7u\n"
+       "  Black wins:  %7u\n"
+       "  White wins:  %7u\n"
+       "  Drawn:       %7u\n"
+       "  Black Bnz:   %7u\n"
+       "  White Bnz:   %7u\n", nblack_win + nwhite_win + ndraw + ninvalid,
+       ninvalid, nblack_win, nwhite_win, ndraw, nbnz_black, nbnz_white );
+
+  return num_tmpfile;
+}
+
+
+static int
+merge_cell( record_move_t *precord_move, FILE **ppf, int num_tmpfile )
+{
+  double dscale;
+  record_move_t swap;
+  cell_t acell[101];
+  uint64_t key;
+  unsigned int book_moves, book_positions, move, size_data, size_section;
+  unsigned int max_size_section, nwin, nwin_bnz, ngame, ngame_bnz, position;
+  unsigned int u, norm;
+  int i, j, iret, ibook_section, imin, nmove;
+  unsigned short s;
+
+  for ( i = 0; i < num_tmpfile; i++ )
+    {
+      iret = read_a_cell( acell + i, ppf[i] );
+      if ( iret < 0 ) { return iret; }
+    }
+  
+  imin             = find_min_cell( acell, num_tmpfile );
+  position         = BK_SIZE_INDEX * NUM_SECTION;
+  max_size_section = book_moves = book_positions = 0;
+  for ( ibook_section = 0; ibook_section < NUM_SECTION; ibook_section++ ) {
+    size_section = 0;
+    for (;;) {
+      key  = acell[imin].key;
+      i    = (int)( (unsigned int)key & (unsigned int)(NUM_SECTION-1) );
+      if ( i != ibook_section || key == UINT64_MAX ) { break; }
+      
+      nwin = nmove = nwin_bnz = ngame = ngame_bnz = precord_move[0].move = 0;
+      do {
+       move = (unsigned int)acell[imin].smove;
+       for ( i = 0; precord_move[i].move && precord_move[i].move != move;
+             i++ );
+       if ( ! precord_move[i].move )
+         {
+           precord_move[i].nwin     = precord_move[i].ngame     = 0;
+           precord_move[i].nwin_bnz = precord_move[i].ngame_bnz = 0;
+           precord_move[i].move     = move;
+           precord_move[i+1].move   = 0;
+           nmove++;
+         }
+
+       if ( acell[imin].result & b0010 )
+         {
+           if ( acell[imin].result & b0100 )
+             {
+               precord_move[i].nwin_bnz += 1;
+               nwin_bnz                 += 1;
+             }
+           precord_move[i].nwin     += 1;
+           nwin                     += 1;
+         }
+
+       if ( acell[imin].result & b0100 )
+         {
+           precord_move[i].ngame_bnz += 1;
+           ngame_bnz                 += 1;
+         }
+       precord_move[i].ngame += 1;
+       ngame                 += 1;
+
+       iret = read_a_cell( acell + imin, ppf[imin] );
+       if ( iret < 0 ) { return iret; }
+       
+       imin = find_min_cell( acell, num_tmpfile );
+      } while ( key == acell[imin].key );
+
+#if defined(BK_COM)
+      while ( nmove > 1 && ngame_bnz >= 128 )
+       {
+         double max_rate, rate;
+
+         max_rate = 0.0;
+         for ( i = 0; i < nmove; i++ )
+           {
+             rate = ( (double)precord_move[i].nwin_bnz
+                      / (double)( precord_move[i].ngame_bnz + 7 ) );
+             if ( rate > max_rate ) { max_rate = rate; }
+           }
+         if ( max_rate < 0.1 ) { break; }
+
+         max_rate *= 0.85;
+         i = 0;
+         do {
+           rate = ( (double)precord_move[i].nwin_bnz
+                    / (double)( precord_move[i].ngame_bnz + 7 ) );
+           
+           if ( rate > max_rate ) { i++; }
+           else {
+             precord_move[i] = precord_move[nmove-1];
+             nmove -= 1;
+           }
+         } while ( i < nmove );
+
+         break;
+       }
+#endif
+      if ( ! nmove ) { continue; }
+      
+      i = 0;
+      do {
+       if ( move_selection( precord_move + i, ngame, nwin ) ) { i++; }
+       else {
+         precord_move[i] = precord_move[nmove-1];
+         nmove -= 1;
+       }
+      } while ( i < nmove );
+
+      if ( ! nmove ) { continue; }
+
+      size_data = BK_SIZE_HEADER + BK_SIZE_MOVE * nmove;
+      if ( size_section + size_data > MAX_SIZE_SECTION
+          || size_data > UCHAR_MAX )
+       {
+         str_error = "book_section buffer overflow";
+         return -2;
+       }
+      if ( nmove > BK_MAX_MOVE )
+       {
+         str_error = "BK_MAX_MOVE is too small";
+         return -2;
+       }
+
+      /* insertion sort by nwin */
+      precord_move[nmove].nwin = 0;
+      for ( i = nmove-2; i >= 0; i-- )
+       {
+         u    = precord_move[i].nwin;
+         swap = precord_move[i];
+         for ( j = i+1; precord_move[j].nwin > u; j++ )
+           {
+             precord_move[j-1] = precord_move[j];
+           }
+         precord_move[j-1] = swap;
+       }
+
+      /* normalize nwin */
+      for ( norm = 0, i = 0; i < nmove; i++ ) { norm += precord_move[i].nwin; }
+      dscale = (double)USHRT_MAX / (double)norm;
+      for ( norm = 0, i = 0; i < nmove; i++ )
+       {
+         u = (unsigned int)( (double)precord_move[i].nwin * dscale );
+         if ( ! u )           { u = 1U; }
+         if ( u > USHRT_MAX ) { u = USHRT_MAX; }
+         
+         precord_move[i].nwin = u;
+         norm                += u;
+       }
+      if ( norm > precord_move[0].nwin + USHRT_MAX )
+       {
+         str_error = "normalization error\n";
+         return -2;
+       }
+      precord_move[0].nwin += USHRT_MAX - norm;
+
+      book_section[size_section+0] = (unsigned char)size_data;
+      *(uint64_t *)(book_section+size_section+1) = key;
+
+      for ( u = size_section+BK_SIZE_HEADER, i = 0; i < nmove;
+           u += BK_SIZE_MOVE, i++ )
+       {
+         *(unsigned short *)(book_section+u)
+           = (unsigned short)precord_move[i].move;
+         *(unsigned short *)(book_section+u+2)
+           = (unsigned short)precord_move[i].nwin;
+       }
+      book_positions += 1;
+      book_moves     += nmove;
+      size_section   += size_data;
+    }
+    if ( fseek( pf_book, BK_SIZE_INDEX * ibook_section, SEEK_SET ) == EOF )
+      {
+       str_error = str_io_error;
+       return -2;
+      }
+    if ( fwrite( &position, sizeof(unsigned int), 1, pf_book ) != 1 )
+      {
+       str_error = str_io_error;
+       return -2;
+      }
+    s = (unsigned short)size_section;
+    if ( fwrite( &s, sizeof(unsigned short), 1, pf_book ) != 1 )
+      {
+       str_error = str_io_error;
+       return -2;
+      }
+    if ( fseek( pf_book, position, SEEK_SET ) == EOF )
+      {
+       str_error = str_io_error;
+       return -2;
+      }
+    if ( fwrite( &book_section, sizeof(unsigned char), (size_t)size_section,
+                pf_book ) != (size_t)size_section )
+      {
+       str_error = str_io_error;
+       return -2;
+      }
+
+    if ( size_section > max_size_section ) { max_size_section = size_section; }
+    position += size_section;
+  }
+  
+  Out( "Positions in the book:  %u\n", book_positions );
+  Out( "Moves in the book:      %u\n", book_moves );
+  Out( "Max. size of a section: %d\n", max_size_section );
+  
+  return 1;
+}
+
+
+static int
+move_selection( const record_move_t *p, int ngame, int nwin )
+{
+  double total_win_norm, win_norm, win, game, win_move, game_move;
+
+#if defined(BK_SMALL)
+  if ( ! p->nwin || p->ngame < 3 ) { return 0; }
+#else
+  if ( ! p->nwin || p->ngame < 2 ) { return 0; }
+#endif
+
+  win       = (double)nwin;
+  game      = (double)ngame;
+  win_move  = (double)p->nwin;
+  game_move = (double)p->ngame;
+
+  total_win_norm = win      * game_move;
+  win_norm       = win_move * game;
+  if ( win_norm < total_win_norm * 0.85 ) { return 0; }
+
+  return 1;
+}
+
+
+static int
+find_min_cell( const cell_t *pcell, int num_tmpfile )
+{
+  int imin, i;
+
+  imin = 0;
+  for ( i = 1; i < num_tmpfile; i++ )
+    {
+      if ( compare( pcell+imin, pcell+i ) == 1 ) { imin = i; }
+    }
+  return imin;
+}
+
+
+static int
+read_a_cell( cell_t *pcell, FILE *pf )
+{
+  if ( fread( &pcell->key, sizeof(uint64_t), 1, pf ) != 1 )
+    {
+      if ( feof( pf ) )
+       {
+         pcell->key = UINT64_MAX;
+         return 1;
+       }
+      str_error = str_io_error;
+      return -2;
+    }
+  if ( fread( &pcell->smove, sizeof(unsigned short), 1, pf ) != 1 )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  if ( fread( &pcell->result, sizeof(unsigned char), 1, pf ) != 1 )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  return 1;
+}
+
+
+static int
+examine_game( tree_t * restrict ptree, record_t *pr, int *presult,
+             unsigned int *pmoves )
+{
+  rpos_t rpos;
+  int iret, istatus, is_lost, is_win;
+  unsigned int moves;
+
+  *presult = -2;
+
+  iret = record_getpos( pr, &rpos );
+  if ( iret < 0 ) { return iret; }
+
+  is_lost = is_win = 0;
+  moves = 0;
+  do {
+    istatus = in_CSA( ptree, pr, NULL, flag_detect_hang );
+    if ( istatus < 0 )
+      {
+       /* the game is end, however the record is invalid */
+       if ( strstr( str_error, str_bad_record ) != NULL
+            && ( game_status & mask_game_end ) )
+         {
+           break;
+         }
+
+       /* a hang-king and a double-pawn are counted as a lost game */
+       if ( strstr( str_error, str_king_hang ) != NULL
+            || strstr( str_error, str_double_pawn )  != NULL
+            || strstr( str_error, str_mate_drppawn ) != NULL )
+         {
+           is_lost = 1;
+           break;
+         }
+
+       return istatus;
+      }
+    /* previous move had an error, count as a won game */
+    else if ( istatus == record_error )
+      {
+       is_win = 1;
+       break;
+      }
+    else if ( istatus == record_misc ) { moves++; }
+  } while ( istatus != record_next && istatus != record_eof );
+
+  if ( istatus != record_next && istatus != record_eof )
+    {
+      istatus = record_wind( pr );
+      if ( istatus < 0 ) { return istatus; }
+    }
+
+  if ( ! ( is_lost || is_win || ( game_status & mask_game_end ) ) )
+    {
+      return istatus;
+    }
+
+  if      ( is_win ) { *presult = root_turn ? -1 : 1; }
+  else if ( is_lost || ( game_status & ( flag_mated | flag_resigned ) ) )
+    {
+      *presult = root_turn ? 1 : -1;
+    }
+  else { *presult = 0; }
+
+  *pmoves = moves;
+
+  iret = record_setpos( pr, &rpos );
+  if ( iret < 0 ) { return iret; }
+
+  return istatus;
+}
+
+
+static int
+dump_cell( cell_t *pcell, int ncell, int num_tmpfile )
+{
+  char str_filename[SIZE_FILENAME];
+  FILE *pf;
+  int i, iret;
+
+  Out( " sort" );
+  qsort( pcell, ncell, sizeof(cell_t), compare );
+
+  Out( " dump", str_filename );
+  snprintf( str_filename, SIZE_FILENAME, "tmp%02d.bin", num_tmpfile );
+  pf = file_open( str_filename, "wb" );
+  if ( pf == NULL ) { return -2; }
+
+  for ( i = 0; i < ncell; i++ )
+    {
+      if ( fwrite( &pcell[i].key, sizeof(uint64_t), 1, pf ) != 1 )
+       {
+         file_close( pf );
+         str_error = str_io_error;
+         return -2;
+       }
+      if ( fwrite( &pcell[i].smove, sizeof(unsigned short), 1, pf ) != 1 )
+       {
+         file_close( pf );
+         str_error = str_io_error;
+         return -2;
+       }
+      if ( fwrite( &pcell[i].result, sizeof(unsigned char), 1, pf ) != 1 )
+       {
+         file_close( pf );
+         str_error = str_io_error;
+         return -2;
+       }
+    }
+
+  iret = file_close( pf );
+  if ( iret < 0 ) { return iret; }
+
+  Out( " done (%s)\n", str_filename );
+
+  return 1;
+}
+
+
+static int CONV_CDECL
+compare( const void * p1, const void * p2 )
+{
+  const cell_t * pcell1 = p1;
+  const cell_t * pcell2 = p2;
+  unsigned int u1, u2;
+
+  u1 = (unsigned int)pcell1->key & (unsigned int)(NUM_SECTION-1);
+  u2 = (unsigned int)pcell2->key & (unsigned int)(NUM_SECTION-1);
+
+  if ( u1 < u2 ) { return -1; }
+  if ( u1 > u2 ) { return  1; }
+  if ( pcell1->key < pcell2->key ) { return -1; }
+  if ( pcell1->key > pcell2->key ) { return  1; }
+
+  return 0;
+}
+
+
+static unsigned int
+move2bm( unsigned int move, int turn, int is_flip )
+{
+  ft_t ft;
+  unsigned int bmove;
+  int is_promote;
+
+  ft.to      = I2To(move);
+  ft.from    = I2From(move);
+  is_promote = I2IsPromote(move);
+
+  ft = flip_ft( ft, turn, is_flip );
+
+  bmove = (unsigned int)( is_promote | From2Move(ft.from) | ft.to );
+
+  return bmove;
+}
+
+
+#endif /* no MINIMUM */
diff --git a/book_anti.csa b/book_anti.csa
new file mode 100644 (file)
index 0000000..22d1789
--- /dev/null
@@ -0,0 +1,6 @@
+PI, +, +6978KI, -8384FU, %TORYO, /
+PI, +, +7776FU, -4132KI, +2726FU, %TORYO, /
+PI, +, +7776FU, -4132KI, +6978KI, %TORYO, /
+PI, +, +7776FU, -7162GI, -6766FU, %TORYO, /
+PI, +, +7776FU, -3334FU, +3948GI, -4344FU, %TORYO, /
+PI, +, +5968OU, -3334FU, %TORYO
diff --git a/csa.c b/csa.c
new file mode 100644 (file)
index 0000000..e99f953
--- /dev/null
+++ b/csa.c
@@ -0,0 +1,965 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <time.h>
+#include "shogi.h"
+
+static void out_CSA_header( const tree_t * restrict ptree, record_t *pr );
+static int str2piece( const char *str );
+static int skip_comment( record_t *pr );
+static int read_char( record_t *pr );
+static int read_CSA_line( record_t *pr, char *str );
+static int in_CSA_header( tree_t * restrict ptree, record_t *pr, int flag );
+static int read_board_rep2( const char *str_line, min_posi_t *pmin_posi );
+static int read_board_rep3( const char *str_line, min_posi_t *pmin_posi );
+
+int
+read_record( tree_t * restrict ptree, const char *str_file,
+            unsigned int moves, int flag )
+{
+  record_t record;
+  int iret;
+
+  iret = record_open( &record, str_file, mode_read, NULL, NULL );
+  if ( iret < 0 ) { return iret; }
+
+  if ( ! moves )
+    {
+      iret = in_CSA_header( ptree, &record, flag );
+      if ( iret < 0 )
+       {
+         record_close( &record );
+         return iret;
+       }
+    }
+  else do {
+    iret = in_CSA( ptree, &record, NULL, flag );
+    if ( iret < 0 )
+      {
+       record_close( &record );
+       return iret;
+      }
+  } while ( iret != record_next
+           && iret != record_eof
+           && moves > record.moves );
+  
+  return record_close( &record );
+}
+
+
+int
+record_open( record_t *pr, const char *str_file, record_mode_t record_mode,
+            const char *str_name1, const char *str_name2 )
+{
+  pr->games = pr->moves = pr->lines = 0;
+  pr->str_name1[0] = '\0';
+  pr->str_name2[0] = '\0';
+
+  if ( str_name1 )
+    {
+      strncpy( pr->str_name1, str_name1, SIZE_PLAYERNAME-1 );
+      pr->str_name1[SIZE_PLAYERNAME-1] = '\0';
+    }
+  
+  if ( str_name2 )
+    {
+      strncpy( pr->str_name2, str_name2, SIZE_PLAYERNAME-1 );
+      pr->str_name2[SIZE_PLAYERNAME-1] = '\0';
+    }
+
+  if ( record_mode == mode_write )
+    {
+      pr->pf = file_open( str_file, "w" );
+      if ( pr->pf == NULL ) { return -2; }
+    }
+  else if ( record_mode == mode_read_write )
+    {
+      pr->pf = file_open( str_file, "wb+" );
+      if ( pr->pf == NULL ) { return -2; }
+    }
+  else {
+    assert( record_mode == mode_read );
+
+    pr->pf = file_open( str_file, "rb" );
+    if ( pr->pf == NULL ) { return -2; }
+  }
+
+  return 1;
+}
+
+
+int
+record_close( record_t *pr )
+{
+  int iret = file_close( pr->pf );
+  pr->pf = NULL;
+  return iret;
+}
+
+
+void
+out_CSA( tree_t * restrict ptree, record_t *pr, unsigned int move )
+{
+  const char *str_move;
+  unsigned int sec;
+
+  /* print move */
+  if ( move == MOVE_RESIGN )
+    {
+      if ( ! pr->moves ) { out_CSA_header( ptree, pr ); }
+      fprintf( pr->pf, "%s\n", str_resign );
+      pr->lines++;
+    }
+  else {
+    if ( ! pr->moves )
+      {
+       root_turn = Flip(root_turn);
+       UnMakeMove( root_turn, move, 1 );
+       out_CSA_header( ptree, pr );
+       MakeMove( root_turn, move, 1 );
+       root_turn = Flip(root_turn);
+      }
+    str_move = str_CSA_move( move );
+    fprintf( pr->pf, "%c%s\n", ach_turn[Flip(root_turn)], str_move );
+    pr->lines++;
+    pr->moves++;
+  }
+
+  /* print time */
+  sec = root_turn ? sec_b_total : sec_w_total;
+
+  fprintf( pr->pf, "T%-7u,'%03u:%02u \n", sec_elapsed, sec / 60U, sec % 60U );
+  pr->lines++;
+
+  /* print repetition or mate status */
+  if ( game_status & flag_mated )
+    {
+      fprintf( pr->pf, "%%TSUMI\n" );
+      pr->lines++;
+    }
+  else if ( game_status & flag_drawn )
+    {
+      fprintf( pr->pf, "%s\n", str_repetition );
+      pr->lines++;
+    }
+
+  fflush( pr->pf );
+}
+
+
+int
+record_wind( record_t *pr )
+{
+  char str_line[ SIZE_CSALINE ];
+  int iret;
+  for (;;)
+    {
+      iret = read_CSA_line( pr, str_line );
+      if ( iret < 0 ) { return iret; }
+      if ( ! iret ) { return record_eof; }
+      if ( ! strcmp( str_line, "/" ) ) { break; }
+    }
+  pr->games++;
+  pr->moves = 0;
+  return record_next;
+}
+
+
+#if ! defined(MINIMUM)
+int
+record_rewind( record_t *pr )
+{
+  pr->games = pr->moves = pr->lines = 0;
+  if ( fseek( pr->pf, 0, SEEK_SET ) ) { return -2; }
+
+  return 1;
+}
+
+
+int
+record_getpos( record_t *pr, rpos_t *prpos )
+{
+  if ( fgetpos( pr->pf, &prpos->fpos ) )
+    {
+      str_error = "fgetpos() failed.";
+      return -2;
+    }
+  prpos->games = pr->games;
+  prpos->moves = pr->moves;
+  prpos->lines = pr->lines;
+
+  return 1;
+}
+
+
+int
+record_setpos( record_t *pr, const rpos_t *prpos )
+{
+  if ( fsetpos( pr->pf, &prpos->fpos ) )
+    {
+      str_error = "fsetpos() failed.";
+      return -2;
+    }
+  pr->games = prpos->games;
+  pr->moves = prpos->moves;
+  pr->lines = prpos->lines;
+
+  return 1;
+}
+#endif /* no MINIMUM */
+
+
+int
+in_CSA( tree_t * restrict ptree, record_t *pr, unsigned int *pmove, int flag )
+{
+  char str_line[ SIZE_CSALINE ];
+  char *ptr;
+  unsigned int move;
+  long l;
+  int iret;
+  
+  if ( pr->moves == 0 )
+    {
+      iret = in_CSA_header( ptree, pr, flag );
+      if ( iret < 0 ) { return iret; }
+    }
+
+  do {
+    iret = read_CSA_line( pr, str_line );
+    if ( iret < 0 ) { return iret; }
+    if ( ! iret ) { return record_eof; }
+    if ( ! strcmp( str_line, str_resign ) )
+      {
+       game_status |= flag_resigned;
+       return record_resign;
+      }
+    if ( ! strcmp( str_line, str_repetition )
+        || ! strcmp( str_line, str_jishogi ) )
+      {
+       game_status |= flag_drawn;
+       return record_drawn;
+      }
+    if ( ! strcmp( str_line, str_record_error ) )
+      {
+       return record_error;
+      }
+  } while ( str_line[0] == 'T' || str_line[0] == '%' );
+
+  if ( ! strcmp( str_line, "/" ) )
+    {
+      pr->games++;
+      pr->moves = 0;
+      return record_next;
+    }
+
+  if ( game_status & mask_game_end )
+    {
+      snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+               pr->lines, str_bad_record );
+      str_error = str_message;
+      return -2;
+    }
+
+  iret = interpret_CSA_move( ptree, &move, str_line+1 );
+  if ( iret < 0 )
+    {
+      snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+               pr->lines, str_error );
+      str_error = str_message;
+      return -2;
+    }
+  if ( pmove != NULL ) { *pmove = move; }
+
+  /* do time */
+  if ( flag & flag_time )
+    {
+      iret = read_CSA_line( pr, str_line );
+      if ( iret < 0 ) { return iret; }
+      if ( ! iret )
+       {
+         snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+                   pr->lines, str_unexpect_eof );
+         str_error = str_message;
+         return -2;
+       }
+      if ( str_line[0] != 'T' )
+       {
+         snprintf( str_message, SIZE_MESSAGE, str_fmt_line, pr->lines,
+                  "Time spent is not available." );
+         str_error = str_message;
+         return -2;
+       }
+      l = strtol( str_line+1, &ptr, 0 );
+      if ( ptr == str_line+1 || l == LONG_MAX || l < 0 )
+       {
+         snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+                   pr->lines, str_bad_record );
+         str_error = str_message;
+         return -2;
+       }
+    }
+  else { l = 0; }
+  sec_elapsed = (unsigned int)l;
+  if ( root_turn ) { sec_w_total += (unsigned int)l; }
+  else             { sec_b_total += (unsigned int)l; }
+
+  iret = make_move_root( ptree, move, flag & ~flag_time );
+  if ( iret < 0 )
+    {
+      snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+               pr->lines, str_error );
+      str_error = str_message;
+      return iret;
+    }
+
+  pr->moves++;
+
+  return record_misc;
+}
+
+
+int
+interpret_CSA_move( tree_t * restrict ptree, unsigned int *pmove,
+                   const char *str )
+{
+  int ifrom_file, ifrom_rank, ito_file, ito_rank, ipiece;
+  int ifrom, ito;
+  unsigned int move;
+  unsigned int *pmove_last;
+  unsigned int *p;
+
+  ifrom_file = str[0]-'0';
+  ifrom_rank = str[1]-'0';
+  ito_file   = str[2]-'0';
+  ito_rank   = str[3]-'0';
+
+  ito_file   = 9 - ito_file;
+  ito_rank   = ito_rank - 1;
+  ito        = ito_rank * 9 + ito_file;
+  ipiece     = str2piece( str+4 );
+  if ( ipiece < 0 )
+    {
+      str_error = str_illegal_move;
+      return -2;
+    }
+
+  if ( ! ifrom_file && ! ifrom_rank )
+    {
+      move  = To2Move(ito) | Drop2Move(ipiece);
+      ifrom = nsquare;
+    }
+  else {
+    ifrom_file = 9 - ifrom_file;
+    ifrom_rank = ifrom_rank - 1;
+    ifrom      = ifrom_rank * 9 + ifrom_file;
+    if ( abs(BOARD[ifrom]) + promote == ipiece )
+      {
+       ipiece -= promote;
+       move    = FLAG_PROMO;
+      }
+    else { move = 0; }
+
+    move |= ( To2Move(ito) | From2Move(ifrom) | Cap2Move(abs(BOARD[ito]))
+             | Piece2Move(ipiece) );
+  }
+
+  *pmove = 0;
+  pmove_last = ptree->amove;
+  pmove_last = GenCaptures(root_turn, pmove_last );
+  pmove_last = GenNoCaptures(root_turn, pmove_last );
+  pmove_last = GenCapNoProEx2(root_turn, pmove_last );
+  pmove_last = GenNoCapNoProEx2(root_turn, pmove_last );
+  pmove_last = GenDrop( root_turn, pmove_last );
+  for ( p = ptree->amove; p < pmove_last; p++ )
+    {
+      if ( *p == move )
+       {
+         *pmove = move;
+         break;
+       }
+    }
+    
+  if ( ! *pmove )
+    {
+      str_error = str_illegal_move;
+      if ( ipiece == pawn
+          && ifrom == nsquare
+          && ! BOARD[ito]
+          && ( root_turn ? IsHandPawn(HAND_W) : IsHandPawn(HAND_B) ) )
+       {
+         unsigned int u;
+
+         if ( root_turn )
+           {
+             u = BBToU( BB_WPAWN_ATK );
+             if ( u & (mask_file1>>ito_file) )
+               {
+                 str_error = str_double_pawn;
+               }
+             else if ( BOARD[ito+nfile] == king )
+               {
+                 str_error = str_mate_drppawn;
+               }
+           }
+         else {
+           u = BBToU( BB_BPAWN_ATK );
+           if ( u & (mask_file1>>ito_file) ) { str_error = str_double_pawn; }
+           else if ( BOARD[ito-nfile] == -king )
+             {
+               str_error = str_mate_drppawn;
+             }
+         }
+       }
+      return -2;
+    }
+  
+  return 1;
+}
+
+
+const char *
+str_CSA_move_plus( tree_t * restrict ptree, unsigned int move, int ply,
+                  int turn )
+{
+  static char str[ 13 ];
+  const unsigned int *pmove_last;
+  unsigned int amove[ MAX_LEGAL_EVASION ];
+  char *p;
+  int is_promo, ipiece_cap, ipiece_move, ifrom, ito, turn_next;
+
+  is_promo    = (int)I2IsPromote(move);
+  ipiece_move = (int)I2PieceMove(move);
+  ifrom       = (int)I2From(move);
+  ito         = (int)I2To(move);
+  ipiece_cap  = (int)UToCap(move);
+  turn_next   = Flip( turn );
+
+  if ( is_promo && ipiece_cap )
+    {
+      snprintf( str, 13, "%d%d%d%d%spx%s",
+              9-aifile[ifrom], airank[ifrom]+1,
+              9-aifile[ito],   airank[ito]  +1,
+              astr_table_piece[ ipiece_move + promote ],
+              astr_table_piece[ ipiece_cap ] );
+      p = str + 10;
+    }
+  else if ( ipiece_cap )
+    {
+      snprintf( str, 13, "%d%d%d%d%sx%s",
+              9-aifile[ifrom], airank[ifrom]+1,
+              9-aifile[ito],   airank[ito]  +1,
+              astr_table_piece[ ipiece_move ],
+              astr_table_piece[ ipiece_cap ] );
+      p = str + 9;
+    }
+  else if ( is_promo )
+    {
+      snprintf( str, 13, "%d%d%d%d%sp",
+              9-aifile[ifrom], airank[ifrom]+1,
+              9-aifile[ito],   airank[ito]  +1,
+              astr_table_piece[ ipiece_move + promote ] );
+      p = str + 7;
+    }
+  else if ( ifrom < nsquare )
+    {
+      snprintf( str, 13, "%d%d%d%d%s",
+              9-aifile[ifrom], airank[ifrom]+1,
+              9-aifile[ito],   airank[ito]  +1,
+              astr_table_piece[ ipiece_move ] );
+      p = str + 6;
+    }
+  else {
+    snprintf( str, 13, "00%d%d%s", 9-aifile[ito], airank[ito]+1,
+            astr_table_piece[ From2Drop(ifrom) ] );
+    p = str + 6;
+  }
+
+  MakeMove( turn, move, ply );
+  if ( InCheck( turn_next ) )
+    {
+      pmove_last = GenEvasion( turn_next, amove );
+      if ( pmove_last == amove ) { *p++ = '#'; }
+      else                       { *p++ = '!'; }
+      *p   = '\0';
+    }
+  UnMakeMove( turn, move, ply );
+
+  return str;
+}
+
+
+const char *
+str_CSA_move( unsigned int move )
+{
+  static char str[7];
+  int ifrom, ito, ipiece_move, is_promote;
+
+  is_promote  = (int)I2IsPromote(move);
+  ipiece_move = (int)I2PieceMove(move);
+  ifrom       = (int)I2From(move);
+  ito         = (int)I2To(move);
+  
+  if ( is_promote )
+    {
+      snprintf( str, 7, "%d%d%d%d%s",
+               9-aifile[ifrom], airank[ifrom]+1,
+               9-aifile[ito],   airank[ito]  +1,
+               astr_table_piece[ ipiece_move + promote ] );
+    }
+  else if ( ifrom < nsquare )
+    {
+      snprintf( str, 7, "%d%d%d%d%s",
+               9-aifile[ifrom], airank[ifrom]+1,
+               9-aifile[ito],   airank[ito]  +1,
+               astr_table_piece[ ipiece_move ] );
+    }
+  else {
+    snprintf( str, 7, "00%d%d%s",
+             9-aifile[ito], airank[ito]+1,
+             astr_table_piece[ From2Drop(ifrom) ] );
+  }
+  
+  return str;
+}
+
+
+int
+read_board_rep1( const char *str_line, min_posi_t *pmin_posi )
+{
+  const char *p;
+  char str_piece[3];
+  int piece, ifile, irank, isquare;
+  signed char board[nsquare];
+
+  memcpy( board, &min_posi_no_handicap.asquare, nsquare );
+
+  for ( p = str_line + 2; p[0] != '\0'; p += 4 )
+    {
+      if ( p[1] == '\0' || p[2] == '\0' || p[3] == '\0' )
+       {
+         str_error = str_bad_board;
+         return -2;
+       }
+      str_piece[0] = p[2];
+      str_piece[1] = p[3];
+      str_piece[2] = '\0';
+      piece        = str2piece( str_piece );
+      ifile        = p[0]-'0';
+      irank        = p[1]-'0';
+      ifile        = 9 - ifile;
+      irank        = irank - 1;
+      isquare      = irank * nfile + ifile;
+      if ( piece == -2 || ifile < file1 || ifile > file9 || irank < rank1
+          || irank > rank9 || abs(board[isquare]) != piece )
+       {
+         str_error = str_bad_board;
+         return -2;
+       }
+      board[isquare] = empty;
+    }
+  
+  for ( isquare = 0; isquare < nsquare; isquare++ ) if ( board[isquare] )
+    {
+      if ( pmin_posi->asquare[isquare] )
+       {
+         str_error = str_bad_board;
+         return -2;
+       }
+      pmin_posi->asquare[isquare] = board[isquare];
+    }
+  
+  return 1;
+}
+
+
+static void
+out_CSA_header( const tree_t * restrict ptree, record_t *pr )
+{
+  time_t t;
+
+  fprintf( pr->pf, "'Bonanza version " BNZ_VER "\n" );
+
+  if ( pr->str_name1[0] != '\0' )
+    {
+      fprintf( pr->pf, "N+%s\n", pr->str_name1 );
+    }
+
+  if ( pr->str_name2[0] != '\0' )
+    {
+      fprintf( pr->pf, "N-%s\n", pr->str_name2 );
+    }
+
+  t = time( NULL );
+  if ( t == (time_t)-1 ) { out_warning( "%s time() faild." ); }
+  else {
+#if defined(_MSC_VER)
+    struct tm tm;
+    localtime_s( &tm, &t );
+    fprintf( pr->pf, "$START_TIME:%4d/%02d/%02d %02d:%02d:%02d\n",
+            tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
+            tm.tm_hour, tm.tm_min, tm.tm_sec );
+#else
+    struct tm *ptm;
+    ptm = localtime( &t );
+    fprintf( pr->pf, "$START_TIME:%4d/%02d/%02d %02d:%02d:%02d\n",
+            ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
+            ptm->tm_hour, ptm->tm_min, ptm->tm_sec );
+#endif
+  }
+
+  if ( ! memcmp( BOARD, min_posi_no_handicap.asquare, nsquare )
+       && min_posi_no_handicap.turn_to_move == root_turn
+       && min_posi_no_handicap.hand_black   == HAND_B
+       && min_posi_no_handicap.hand_white   == HAND_W )
+    {
+      fprintf( pr->pf, "PI\n" );
+      pr->lines++;
+    }
+  else {
+    out_board( ptree, pr->pf, 0, 1 );
+    pr->lines += 10;
+  }
+  
+  if ( root_turn ) { fprintf( pr->pf, "-\n" ); }
+  else             { fprintf( pr->pf, "+\n" ); }
+  pr->lines++;
+}
+
+
+static int
+in_CSA_header( tree_t * restrict ptree, record_t *pr, int flag )
+{
+  min_posi_t min_posi;
+  const char *str_name1, *str_name2;
+  char str_line[ SIZE_CSALINE ];
+  int iret, is_rep1_done, is_rep2_done, is_all_done, i, j;
+
+  for ( i = 0; i < MAX_ANSWER; i++ ) { pr->info.str_move[i][0] = '\0'; }
+  str_name1 = str_name2 = NULL;
+
+  /* version and info */
+  for ( ;; )
+    {
+      iret = read_CSA_line( pr, str_line );
+      if ( iret < 0 ) { return iret; }
+
+      if ( str_line[0] != 'N'
+          && str_line[0] != 'V'
+          && str_line[0] != '$' ) { break; }
+
+      if ( ! memcmp( str_line, "$ANSWER:", 8 ) )
+       {
+         for ( i = 0; i < MAX_ANSWER; i++ )
+           {
+             for ( j = 0; j < 8; j++ )
+               {
+                 pr->info.str_move[i][j] = str_line[8+i*8+j];
+               }
+             pr->info.str_move[i][7] = '\0';
+             if ( str_line[8+i*8+7] == '\0' ) { break; }
+           }
+         if ( i == MAX_ANSWER )
+           {
+             snprintf( str_message, SIZE_MESSAGE, str_fmt_line, pr->lines,
+                      "The number of answers reached MAX_ANSWER." );
+             str_error = str_message;
+             return -2;
+           }
+       }
+      else if ( ! memcmp( str_line, "N+", 2 ) )
+       {
+         strncpy( pr->str_name1, str_line+2, SIZE_PLAYERNAME-1 );
+         pr->str_name1[SIZE_PLAYERNAME-1] = '\0';
+         str_name1 = pr->str_name1;
+       }
+      else if ( ! memcmp( str_line, "N-", 2 ) )
+       {
+         strncpy( pr->str_name2, str_line+2, SIZE_PLAYERNAME-1 );
+         pr->str_name2[SIZE_PLAYERNAME-1] = '\0';
+         str_name2 = pr->str_name2;
+       }
+    }
+  if ( ! iret )
+    {
+      snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+               pr->lines, str_unexpect_eof );
+      str_error = str_message;
+      return -2;
+    }
+
+  /* board representation */
+  memset( &min_posi.asquare, empty, nsquare );
+  min_posi.hand_black = min_posi.hand_white = 0;
+  is_rep1_done = is_rep2_done = is_all_done = 0;
+  while ( str_line[0] == 'P' )
+    {
+      if ( str_line[1] == 'I' && ! is_rep2_done && ! is_all_done )
+       {
+         is_rep1_done = 1;
+         iret = read_board_rep1( str_line, &min_posi );
+       }
+      else if ( isdigit( (int)str_line[1] ) && str_line[1] != '0'
+               && ! is_rep1_done && ! is_all_done )
+       {
+         is_rep2_done = 1;
+         iret = read_board_rep2( str_line, &min_posi );
+       }
+      else if ( str_line[1] == '+' || str_line[1] == '-' )
+       {
+         is_all_done = iret = read_board_rep3( str_line, &min_posi );
+       }
+      else { break; }
+      if ( iret < 0 )
+       {
+         snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+                   pr->lines, str_error );
+         str_error = str_message;
+         return iret;
+       }
+
+      iret = read_CSA_line( pr, str_line );
+      if ( iret < 0 ) { return iret; }
+      if ( ! iret )
+       {
+         snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+                   pr->lines, str_unexpect_eof );
+         str_error = str_message;
+         return -2;
+       }
+    }
+  
+  /* turn to move */
+  if ( strcmp( str_line, "+" ) && strcmp( str_line, "-" ) )
+    {
+      snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+               pr->lines, str_bad_record );
+      str_error = str_message;
+      return -2;
+    }
+  min_posi.turn_to_move = (char)( ( str_line[0] == '+' ) ? black : white );
+
+  return ini_game( ptree, &min_posi, flag, str_name1, str_name2 );
+}
+
+
+static int
+read_board_rep3( const char *str_line, min_posi_t *pmin_posi )
+{
+  int is_all_done, irank, ifile, isquare, piece, n, color;
+  int npawn, nlance, nknight, nsilver, ngold, nbishop, nrook;
+  unsigned int handv, hand_white, hand_black;
+  char str_piece[3];
+
+  is_all_done = 0;
+  str_piece[2] = '\0';
+
+  color = str_line[1] == '+' ? black : white;
+  for ( n = 2; str_line[n] != '\0'; n += 4 ) {
+    if ( str_line[n+1] == '\0' || str_line[n+2] == '\0'
+        || str_line[n+3] == '\0' || is_all_done )
+      {
+       str_error = str_bad_board;
+       return -2;
+      }
+    if ( str_line[n] == '0' && str_line[n+1] == '0'
+        && str_line[n+2] == 'A' && str_line[n+3] == 'L' ) {
+      hand_black = pmin_posi->hand_black;
+      hand_white = pmin_posi->hand_white;
+      npawn   = (int)(I2HandPawn(hand_black)   + I2HandPawn(hand_white));
+      nlance  = (int)(I2HandLance(hand_black)  + I2HandLance(hand_white));
+      nknight = (int)(I2HandKnight(hand_black) + I2HandKnight(hand_white));
+      nsilver = (int)(I2HandSilver(hand_black) + I2HandSilver(hand_white));
+      ngold   = (int)(I2HandGold(hand_black)   + I2HandGold(hand_white));
+      nbishop = (int)(I2HandBishop(hand_black) + I2HandBishop(hand_white));
+      nrook   = (int)(I2HandRook(hand_black)   + I2HandRook(hand_white));
+      for ( isquare = 0; isquare < nsquare; isquare++ )
+       switch ( abs( pmin_posi->asquare[isquare] ) )
+         {
+         case pawn:    case pro_pawn:    npawn++;    break;
+         case lance:   case pro_lance:   nlance++;   break;
+         case knight:  case pro_knight:  nknight++;  break;
+         case silver:  case pro_silver:  nsilver++;  break;
+         case gold:                      ngold++;    break;
+         case bishop:  case horse:       nbishop++;  break;
+         case rook:    case dragon:      nrook++;    break;
+         default:
+           assert( pmin_posi->asquare[isquare] == empty );
+           break;
+         }
+      handv  = flag_hand_pawn   * ( npawn_max   -npawn );
+      handv += flag_hand_lance  * ( nlance_max  -nlance );
+      handv += flag_hand_knight * ( nknight_max -nknight );
+      handv += flag_hand_silver * ( nsilver_max -nsilver );
+      handv += flag_hand_gold   * ( ngold_max   -ngold );
+      handv += flag_hand_bishop * ( nbishop_max -nbishop );
+      handv += flag_hand_rook   * ( nrook_max   -nrook );
+      if ( color ) { pmin_posi->hand_white += handv; }
+      else         { pmin_posi->hand_black += handv; }
+      is_all_done = 1;
+      continue;
+    }
+    
+    ifile        = str_line[n+0]-'0';
+    irank        = str_line[n+1]-'0';
+    str_piece[0] = str_line[n+2];
+    str_piece[1] = str_line[n+3];
+    piece        = str2piece( str_piece );
+    
+    /* hand */
+    if ( ifile == 0 && ifile == 0 )
+      {
+       switch ( piece )
+         {
+         case pawn:    handv = flag_hand_pawn;    break;
+         case lance:   handv = flag_hand_lance;   break;
+         case knight:  handv = flag_hand_knight;  break;
+         case silver:  handv = flag_hand_silver;  break;
+         case gold:    handv = flag_hand_gold;    break;
+         case bishop:  handv = flag_hand_bishop;  break;
+         case rook:    handv = flag_hand_rook;    break;
+         default:
+           str_error = str_bad_board;
+           return -2;
+         }
+       if ( color ) { pmin_posi->hand_white += handv; }
+       else         { pmin_posi->hand_black += handv; }
+      }
+    /* board */
+    else {
+      ifile   = 9 - ifile;
+      irank   = irank - 1;
+      isquare = irank * nfile + ifile;
+      if ( piece == -2 || ifile < file1 || ifile > file9
+          || irank < rank1 || irank > rank9 || pmin_posi->asquare[isquare] )
+       {
+         str_error = str_bad_board;
+         return -2;
+       }
+      pmin_posi->asquare[isquare] = (signed char)( color ? -piece : piece );
+    }
+  }
+  
+  return is_all_done;
+}
+
+
+static int
+read_board_rep2( const char * str_line, min_posi_t *pmin_posi )
+{
+  int irank, ifile, piece;
+  char str_piece[3];
+
+  str_piece[2] = '\0';
+  
+  irank = str_line[1] - '1';
+
+  for ( ifile = 0; ifile < nfile; ifile++ )
+    if ( str_line[2+ifile*3] == '+' || str_line[2+ifile*3] == '-' )
+      {
+       str_piece[0] = str_line[2+ifile*3+1];
+       str_piece[1] = str_line[2+ifile*3+2];
+       piece = str2piece( str_piece );
+       if ( piece < 0 || pmin_posi->asquare[ irank*nfile + ifile ] )
+         {
+           str_error = str_bad_board;
+           return -2;
+         }
+       pmin_posi->asquare[ irank*nfile + ifile ]
+         = (signed char)( str_line[ 2 + ifile*3 ] == '-' ? -piece : piece );
+      }
+    else { pmin_posi->asquare[ irank*nfile + ifile ] = empty; }
+
+  return 1;
+}
+
+
+static int
+str2piece( const char *str )
+{
+  int i;
+
+  for ( i = 0; i < 16; i++ )
+    {
+      if ( ! strcmp( astr_table_piece[i], str ) ) { break; }
+    }
+  if ( i == 0 || i == piece_null || i == 16 ) { i = -2; }
+
+  return i;
+}
+
+
+/* reads a csa line in str, trancates trailing spases.
+ * return value:
+ *   0  EOF, no line is read.
+ *   1  a csa line is read in str
+ *  -2  buffer overflow
+ */
+static int
+read_CSA_line( record_t *pr, char *str )
+{
+  int i, c, do_comma;
+
+  for ( ;; )
+    {
+      c = skip_comment( pr );
+      if ( isgraph( c ) || c == EOF ) { break; }
+    }
+  if ( c == EOF ) { return 0; }
+  
+  do_comma = ( c == 'N' || c == '$' ) ? 0 : 1;
+
+  for ( i = 0; i < SIZE_CSALINE-1; i++ )
+    {
+      if ( c == EOF || c == '\n' || ( do_comma && c == ',' ) ) { break; }
+      str[i] = (char)c;
+      c = read_char( pr );
+    }
+
+  if ( i == SIZE_CSALINE-1 )
+    {
+      snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+               pr->lines, str_ovrflw_line );
+      return -2;
+    }
+
+  i--;
+  while ( isascii( (int)str[i] ) && isspace( (int)str[i] ) ) { i--; }
+  str[i+1] = '\0';
+
+  return 1;
+}
+
+
+static int
+skip_comment( record_t *pr )
+{
+  int c;
+
+  c = read_char( pr );
+  for ( ;; )
+    {
+      if ( c != '\'' ) { break; }
+      for ( ;; )
+       {
+         c = read_char( pr );
+         if ( c == EOF || c == '\n' ) { break; }
+       }
+    }
+  
+  return c;
+}
+
+
+static int
+read_char( record_t *pr )
+{
+  int c;
+
+  c = fgetc( pr->pf );
+  if ( c == '\n' ) { pr->lines++; }
+
+  return c;
+}
diff --git a/data.c b/data.c
new file mode 100644 (file)
index 0000000..97e9500
--- /dev/null
+++ b/data.c
@@ -0,0 +1,327 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+FILE *pf_book;
+FILE *pf_hash;
+uint64_t ehash_tbl[ EHASH_MASK + 1 ];
+unsigned char hash_rejections_parent[ REJEC_MASK+1 ];
+rejections_t  hash_rejections[ REJEC_MASK+1 ];
+trans_table_t *ptrans_table_orig;
+SHARE trans_table_t *ptrans_table;
+history_book_learn_t history_book_learn[ HASH_REG_HIST_LEN ];
+record_t record_problems;
+record_t record_game;
+rand_work_t rand_work;
+root_move_t root_move_list[ MAX_LEGAL_MOVES ];
+pv_t last_pv;
+pv_t last_pv_save;
+slide_tbl_t aslide[ nsquare ];
+bitboard_t abb_b_knight_attacks[ nsquare ];
+bitboard_t abb_b_silver_attacks[ nsquare ];
+bitboard_t abb_b_gold_attacks[ nsquare ];
+bitboard_t abb_w_knight_attacks[ nsquare ];
+bitboard_t abb_w_silver_attacks[ nsquare ];
+bitboard_t abb_w_gold_attacks[ nsquare ];
+bitboard_t abb_king_attacks[ nsquare ];
+bitboard_t abb_bishop_attacks_rl45[ nsquare ][ 128 ];
+bitboard_t abb_bishop_attacks_rr45[ nsquare ][ 128 ];
+bitboard_t abb_file_attacks[ nsquare ][ 128 ];
+bitboard_t abb_obstacle[ nsquare ][ nsquare ];
+bitboard_t abb_mask[ nsquare ];
+bitboard_t abb_mask_rl90[ nsquare ];
+bitboard_t abb_mask_rl45[ nsquare ];
+bitboard_t abb_mask_rr45[ nsquare ];
+bitboard_t abb_plus_rays[ nsquare ];
+bitboard_t abb_minus_rays[ nsquare ];
+uint64_t b_pawn_rand[ nsquare ];
+uint64_t b_lance_rand[ nsquare ];
+uint64_t b_knight_rand[ nsquare ];
+uint64_t b_silver_rand[ nsquare ];
+uint64_t b_gold_rand[ nsquare ];
+uint64_t b_bishop_rand[ nsquare ];
+uint64_t b_rook_rand[ nsquare ];
+uint64_t b_king_rand[ nsquare ];
+uint64_t b_pro_pawn_rand[ nsquare ];
+uint64_t b_pro_lance_rand[ nsquare ];
+uint64_t b_pro_knight_rand[ nsquare ];
+uint64_t b_pro_silver_rand[ nsquare ];
+uint64_t b_horse_rand[ nsquare ];
+uint64_t b_dragon_rand[ nsquare ];
+uint64_t b_hand_pawn_rand[ npawn_max ];
+uint64_t b_hand_lance_rand[ nlance_max ];
+uint64_t b_hand_knight_rand[ nknight_max ];
+uint64_t b_hand_silver_rand[ nsilver_max ];
+uint64_t b_hand_gold_rand[ ngold_max ];
+uint64_t b_hand_bishop_rand[ nbishop_max ];
+uint64_t b_hand_rook_rand[ nrook_max ];
+uint64_t w_pawn_rand[ nsquare ];
+uint64_t w_lance_rand[ nsquare ];
+uint64_t w_knight_rand[ nsquare ];
+uint64_t w_silver_rand[ nsquare ];
+uint64_t w_gold_rand[ nsquare ];
+uint64_t w_bishop_rand[ nsquare ];
+uint64_t w_rook_rand[ nsquare ];
+uint64_t w_king_rand[ nsquare ];
+uint64_t w_pro_pawn_rand[ nsquare ];
+uint64_t w_pro_lance_rand[ nsquare ];
+uint64_t w_pro_knight_rand[ nsquare ];
+uint64_t w_pro_silver_rand[ nsquare ];
+uint64_t w_horse_rand[ nsquare ];
+uint64_t w_dragon_rand[ nsquare ];
+uint64_t w_hand_pawn_rand[ npawn_max ];
+uint64_t w_hand_lance_rand[ nlance_max ];
+uint64_t w_hand_knight_rand[ nknight_max ];
+uint64_t w_hand_silver_rand[ nsilver_max ];
+uint64_t w_hand_gold_rand[ ngold_max ];
+uint64_t w_hand_bishop_rand[ nbishop_max ];
+uint64_t w_hand_rook_rand[ nrook_max ];
+uint64_t node_limit;
+SHARE unsigned int game_status;
+unsigned int move_evasion_pchk;
+unsigned int node_per_second;
+unsigned int node_next_signal;
+unsigned int node_last_check;
+unsigned int hash_mask;
+unsigned int sec_elapsed;
+unsigned int sec_b_total;
+unsigned int sec_w_total;
+unsigned int sec_limit;
+unsigned int sec_limit_up;
+unsigned int sec_limit_depth;
+unsigned int time_last_result;
+unsigned int time_last_check;
+unsigned int time_start;
+unsigned int time_turn_start;
+unsigned int time_limit;
+unsigned int time_max_limit;
+unsigned int time_last_search;
+unsigned int time_last_eff_search;
+unsigned int time_response;
+unsigned int ai_rook_attacks_r0[ nsquare ][ 128 ];
+unsigned int ponder_move;
+int p_value_ex[31];
+int benefit2promo[15];
+int easy_abs;
+int easy_min;
+int easy_max;
+int easy_value;
+SHARE int fmg_misc;
+SHARE int fmg_cap;
+SHARE int fmg_drop;
+SHARE int fmg_mt;
+SHARE int fmg_misc_king;
+SHARE int fmg_cap_king;
+unsigned int ponder_move_list[ MAX_LEGAL_MOVES ];
+int ponder_nmove;
+SHARE int root_abort;
+int root_nrep;
+int root_nmove;
+int root_alpha;
+int root_beta;
+int root_value;
+int root_turn;
+int root_move_cap;
+int root_nfail_high;
+int root_nfail_low;
+int trans_table_age;
+int log2_ntrans_table;
+int n_nobook_move;
+int last_root_value;
+int last_root_value_save;
+int iteration_depth;
+int depth_limit;
+int irecord_game;
+int npawn_box;
+int nlance_box;
+int nknight_box;
+int nsilver_box;
+int ngold_box;
+int nbishop_box;
+int nrook_box;
+int resign_threshold;
+short p_value[31];
+short pc_on_sq[nsquare][pos_n];
+short kkp[nsquare][nsquare][kkp_end];
+unsigned char book_section[ MAX_SIZE_SECTION+1 ];
+unsigned char adirec[ nsquare ][ nsquare ];
+unsigned char is_same[ 16 ][ 16 ];
+char str_cmdline[ SIZE_CMDLINE ];
+char str_message[ SIZE_MESSAGE ];
+char str_buffer_cmdline[ SIZE_CMDBUFFER ];
+const char *str_error;
+
+#if defined(MPV)
+int root_mpv;
+int mpv_num;
+int mpv_width;
+pv_t mpv_pv[ MPV_MAX_PV*2 + 1 ];
+#endif
+
+#if defined(TLP)
+#  if !defined(_WIN32)
+pthread_attr_t pthread_attr;
+#  endif
+lock_t tlp_lock;
+tree_t tlp_atree_work[ TLP_NUM_WORK ];
+tree_t * volatile tlp_ptrees[ TLP_MAX_THREADS ];
+volatile int tlp_abort;
+volatile int tlp_idle;
+volatile int tlp_num;
+int tlp_max;
+int tlp_nsplit;
+int tlp_nabort;
+int tlp_nslot;
+volatile unsigned short tlp_rejections_slot[ REJEC_MASK+1 ];
+#else
+tree_t tree;
+#endif
+
+#if ! defined(_WIN32)
+clock_t clk_tck;
+#endif
+
+#if ! defined(NO_LOGGING)
+FILE *pf_log;
+const char *str_dir_logs = "log";
+#endif
+
+#if defined(CSA_LAN) || defined(MNJ_LAN)
+unsigned int time_last_send;
+#endif
+
+#if defined(CSA_LAN)
+int client_turn;
+int client_ngame;
+int client_max_game;
+long client_port;
+char client_str_addr[256];
+char client_str_id[256];
+char client_str_pwd[256];
+sckt_t sckt_csa;
+#endif
+
+#if defined(MNJ_LAN)
+short mnj_tbl[ MNJ_MASK + 1 ];
+sckt_t sckt_mnj;
+int mnj_posi_id;
+unsigned int mnj_move_last;
+#endif
+
+#if defined(DEKUNOBOU)
+SOCKET dek_socket_in;
+SOCKET dek_s_accept;
+u_long dek_ul_addr;
+unsigned int dek_ngame;
+unsigned int dek_lost;
+unsigned int dek_win;
+int dek_turn;
+u_short dek_ns;
+#endif
+
+check_table_t b_chk_tbl[nsquare];
+check_table_t w_chk_tbl[nsquare];
+
+#if defined(_MSC_VER)
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+#else
+unsigned char aifirst_one[512];
+unsigned char ailast_one[512];
+#endif
+
+#if defined(NDEBUG)
+#  if ! defined(CSASHOGI)
+const char *str_myname = ( "Bonanza " BNZ_VER );
+#  else
+const char *str_myname = ( "Bonanza " BNZ_VER );
+#  endif
+#else
+const char *str_myname = ( "Bonanza " BNZ_VER " Debug Build ("
+                          __TIME__ " " __DATE__ ")" );
+#endif
+
+#if defined(DBG_EASY)
+unsigned int easy_move;
+#endif
+
+const char *str_resign       = "%TORYO";
+const char *str_repetition   = "%SENNICHITE";
+const char *str_jishogi      = "%JISHOGI";
+const char *str_record_error = "%ERROR";
+const char *str_delimiters   = " \t,";
+const char *str_fmt_line     = "Line %u: %s";
+const char *str_on           = "on";
+const char *str_off          = "off";
+const char *str_book         = "book.bin";
+const char *str_hash         = "hash.bin";
+const char *str_fv           = "fv.bin";
+const char *str_book_error   = "invalid opening book";
+const char *str_io_error     = "I/O error";
+const char *str_perpet_check = "perpetual check";
+const char *str_bad_cmdline  = "invalid command line";
+const char *str_busy_think   = "I'm busy in thinking now";
+const char *str_bad_record   = "invalid record of game";
+const char *str_bad_board    = "invalid board representation";
+const char *str_illegal_move = "illegal move";
+const char *str_double_pawn  = "double pawn";
+const char *str_mate_drppawn = "mated by a droped pawn";
+const char *str_unexpect_eof = "unexpected end of file";
+const char *str_king_hang    = "The king is hang.";
+const char *str_game_ended   = "move after a game was concluded";
+const char *str_fopen_error  = "Can't open a file";
+const char *str_ovrflw_line  = "Too many characters in a line.";
+const char *str_warning      = "WARNING: ";
+#if defined(CSA_LAN)
+const char *str_server_err   = "received invalid message from the server";
+#endif
+
+const char *astr_table_piece[16]  = { "* ", "FU", "KY", "KE", "GI", "KI",
+                                     "KA", "HI", "OU", "TO", "NY", "NK",
+                                     "NG", "##", "UM", "RY" };
+
+const char ach_turn[2] = { '+', '-' };
+
+const char ashell_h[ SHELL_H_LEN ] = { 1, 3, 7, 15, 31, 63, 127 };
+
+const short aipos[31] = { e_dragon, e_horse,  0,        e_gold,
+                         e_gold,   e_gold,   e_gold,   0,
+                         e_rook,   e_bishop, e_gold,   e_silver,
+                         e_knight, e_lance,  e_pawn,   0,
+                         f_pawn,   f_lance,  f_knight,
+                         f_silver, f_gold,   f_bishop, f_rook,
+                         0,        f_gold,   f_gold,   f_gold,
+                         f_gold,   0,        f_horse,  f_dragon };
+
+const unsigned char aifile[ nsquare ]= {
+  file1, file2, file3, file4, file5, file6, file7, file8, file9,
+  file1, file2, file3, file4, file5, file6, file7, file8, file9,
+  file1, file2, file3, file4, file5, file6, file7, file8, file9,
+  file1, file2, file3, file4, file5, file6, file7, file8, file9,
+  file1, file2, file3, file4, file5, file6, file7, file8, file9,
+  file1, file2, file3, file4, file5, file6, file7, file8, file9,
+  file1, file2, file3, file4, file5, file6, file7, file8, file9,
+  file1, file2, file3, file4, file5, file6, file7, file8, file9,
+  file1, file2, file3, file4, file5, file6, file7, file8, file9 };
+
+const unsigned char airank[ nsquare ]= {
+  rank1, rank1, rank1, rank1, rank1, rank1, rank1, rank1, rank1,
+  rank2, rank2, rank2, rank2, rank2, rank2, rank2, rank2, rank2,
+  rank3, rank3, rank3, rank3, rank3, rank3, rank3, rank3, rank3,
+  rank4, rank4, rank4, rank4, rank4, rank4, rank4, rank4, rank4,
+  rank5, rank5, rank5, rank5, rank5, rank5, rank5, rank5, rank5,
+  rank6, rank6, rank6, rank6, rank6, rank6, rank6, rank6, rank6,
+  rank7, rank7, rank7, rank7, rank7, rank7, rank7, rank7, rank7,
+  rank8, rank8, rank8, rank8, rank8, rank8, rank8, rank8, rank8,
+  rank9, rank9, rank9, rank9, rank9, rank9, rank9, rank9, rank9 };
+
+const min_posi_t min_posi_no_handicap = {
+  0,0,0,
+  { -lance, -knight, -silver, -gold, -king, -gold, -silver, -knight, -lance,
+    empty, -rook, empty, empty, empty, empty, empty, -bishop, empty,
+    -pawn, -pawn, -pawn, -pawn, -pawn, -pawn, -pawn, -pawn, -pawn,
+    empty, empty, empty, empty, empty, empty, empty, empty, empty,
+    empty, empty, empty, empty, empty, empty, empty, empty, empty,
+    empty, empty, empty, empty, empty, empty, empty, empty, empty,
+    pawn, pawn, pawn, pawn, pawn, pawn, pawn, pawn, pawn,
+    empty, bishop, empty, empty, empty, empty, empty, rook, empty,
+    lance, knight, silver, gold, king, gold, silver, knight, lance } };
diff --git a/debug.c b/debug.c
new file mode 100644 (file)
index 0000000..d18b86f
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,242 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+#if !defined(NDEBUG)
+
+#  define DOut(str)                                                          \
+  out_error( "invalid %s: node= %" PRIu64 "\n", str, ptree->node_searched ); \
+  return 0;
+
+#  define CheckNum( piece )                                      \
+  if ( n ## piece ## _max - n ## piece ## _box != n ## piece ) { \
+    DOut( "number of " # piece );                                \
+  }
+
+#  define CheckBoard( PIECE, piece )                           \
+  bb = BB_B ## PIECE;                                          \
+  while( BBToU( bb ) ) {                                       \
+    sq = FirstOne( bb );                                       \
+    Xor( sq, bb );                                             \
+    if ( BOARD[sq] != piece ) { DOut( "BB_B" # PIECE  ); }     \
+  }                                                            \
+  bb = BB_W ## PIECE;                                          \
+  while( BBToU( bb ) ) {                                       \
+    sq = FirstOne( bb );                                       \
+    Xor( sq, bb );                                             \
+    if ( BOARD[sq] != -piece ) { DOut( "BB_W" # PIECE  ); }  \
+  }
+
+int
+exam_bb( const tree_t *ptree )
+{
+  bitboard_t bb;
+  uint64_t hk;
+  int npawn, nlance, nknight, nsilver, ngold, nbishop, nrook, npiece;
+  int sq, mate;
+
+  /* leading zero-bits */
+  if ( root_turn               & ~0x0000001U ) { DOut( "root_turn" ); }
+  if ( HAND_B                  & ~0x01fffffU ) { DOut( "HAND_B" ); }
+  if ( HAND_W                  & ~0x01fffffU ) { DOut( "HAND_W" ); }
+  if ( BBToU(OCCUPIED_FILE)    & ~0x7ffffffU ) { DOut( "OCCUPIED_FILE" ); }
+  if ( BBToU(OCCUPIED_DIAG2)   & ~0x7ffffffU ) { DOut( "OCCUPIED_DIAG2" ); }
+  if ( BBToU(OCCUPIED_DIAG1)   & ~0x7ffffffU ) { DOut( "OCCUPIED_DIAG1" ); }
+
+  if ( BBToU(BB_BOCCUPY)       & ~0x7ffffffU ) { DOut( "BB_BOCCUPY" ); }
+  if ( BBToU(BB_BPAWN_ATK)     & ~0x7ffffffU ) { DOut( "BB_BPAWN_ATK" ); }
+  if ( BBToU(BB_BTGOLD)        & ~0x7ffffffU ) { DOut( "BB_BTGOLD" ); }
+  if ( BBToU(BB_B_HDK)         & ~0x7ffffffU ) { DOut( "BB_B_HDK" ); }
+  if ( BBToU(BB_B_BH)          & ~0x7ffffffU ) { DOut( "BB_B_BH" ); }
+  if ( BBToU(BB_B_RD)          & ~0x7ffffffU ) { DOut( "BB_B_RD" ); }
+  if ( BBToU(BB_BPAWN)         & ~0x7ffffffU ) { DOut( "BB_BPAWN" ); }
+  if ( BBToU(BB_BLANCE)        & ~0x7ffffffU ) { DOut( "BB_BLANCE" ); }
+  if ( BBToU(BB_BKNIGHT)       & ~0x7ffffffU ) { DOut( "BB_BKNIGHT" ); }
+  if ( BBToU(BB_BSILVER)       & ~0x7ffffffU ) { DOut( "BB_BSILVER" ); }
+  if ( BBToU(BB_BGOLD)         & ~0x7ffffffU ) { DOut( "BB_BGOLD" ); }
+  if ( BBToU(BB_BBISHOP)       & ~0x7ffffffU ) { DOut( "BB_BBISHOP" ); }
+  if ( BBToU(BB_BROOK)         & ~0x7ffffffU ) { DOut( "BB_BROOK" ); }
+  if ( BBToU(BB_BPRO_PAWN)     & ~0x7ffffffU ) { DOut( "BB_BPRO_PAWN" ); }
+  if ( BBToU(BB_BPRO_LANCE)    & ~0x7ffffffU ) { DOut( "BB_BPRO_LANCE" ); }
+  if ( BBToU(BB_BPRO_KNIGHT)   & ~0x7ffffffU ) { DOut( "BB_BPRO_KNIGHT" ); }
+  if ( BBToU(BB_BPRO_SILVER)   & ~0x7ffffffU ) { DOut( "BB_BPRO_SILVER" ); }
+  if ( BBToU(BB_BHORSE)        & ~0x7ffffffU ) { DOut( "BB_BHORSE" ); }
+  if ( BBToU(BB_BDRAGON)       & ~0x7ffffffU ) { DOut( "BB_BDRAGON" ); }
+
+  if ( BBToU(BB_WOCCUPY)       & ~0x7ffffffU ) { DOut( "BB_WOCCUPY" ); }
+  if ( BBToU(BB_WPAWN_ATK)     & ~0x7ffffffU ) { DOut( "BB_WPAWN_ATK" ); }
+  if ( BBToU(BB_WTGOLD)        & ~0x7ffffffU ) { DOut( "BB_WTGOLD" ); }
+  if ( BBToU(BB_W_HDK)         & ~0x7ffffffU ) { DOut( "BB_W_HDK" ); }
+  if ( BBToU(BB_W_BH)          & ~0x7ffffffU ) { DOut( "BB_W_BH" ); }
+  if ( BBToU(BB_W_RD)          & ~0x7ffffffU ) { DOut( "BB_W_RD" ); }
+  if ( BBToU(BB_WPAWN)         & ~0x7ffffffU ) { DOut( "BB_WPAWN" ); }
+  if ( BBToU(BB_WLANCE)        & ~0x7ffffffU ) { DOut( "BB_WLANCE" ); }
+  if ( BBToU(BB_WKNIGHT)       & ~0x7ffffffU ) { DOut( "BB_WKNIGHT" ); }
+  if ( BBToU(BB_WSILVER)       & ~0x7ffffffU ) { DOut( "BB_WSILVER" ); }
+  if ( BBToU(BB_WGOLD)         & ~0x7ffffffU ) { DOut( "BB_WGOLD" ); }
+  if ( BBToU(BB_WBISHOP)       & ~0x7ffffffU ) { DOut( "BB_WBISHOP" ); }
+  if ( BBToU(BB_WROOK)         & ~0x7ffffffU ) { DOut( "BB_WROOK" ); }
+  if ( BBToU(BB_WPRO_PAWN)     & ~0x7ffffffU ) { DOut( "BB_WPRO_PAWN" ); }
+  if ( BBToU(BB_WPRO_LANCE)    & ~0x7ffffffU ) { DOut( "BB_WPRO_LANCE" ); }
+  if ( BBToU(BB_WPRO_KNIGHT)   & ~0x7ffffffU ) { DOut( "BB_WPRO_KNIGHT" ); }
+  if ( BBToU(BB_WPRO_SILVER)   & ~0x7ffffffU ) { DOut( "BB_WPRO_SILVER" ); }
+  if ( BBToU(BB_WHORSE)        & ~0x7ffffffU ) { DOut( "BB_WHORSE" ); }
+  if ( BBToU(BB_WDRAGON)       & ~0x7ffffffU ) { DOut( "BB_WDRAGON" ); }
+
+  if ( BB_BPAWN.p[0]           &  0x7fc0000U ) { DOut( "pawn at rank1" ); }
+  if ( BB_BKNIGHT.p[0]         &  0x7fffe00U ) { DOut( "knight at rank1-2" ); }
+
+  if ( BB_WPAWN.p[2]           &  0x00001ffU ) { DOut( "pawn at rank9" ); }
+  if ( BB_WKNIGHT.p[2]         &  0x003ffffU ) { DOut( "knight at rank8-9" ); }
+
+
+  /* number of pieces */
+  BBOr( bb, BB_BPAWN, BB_WPAWN );
+  BBOr( bb, BB_BPRO_PAWN, bb );
+  BBOr( bb, BB_WPRO_PAWN, bb );
+  npawn = I2HandPawn(HAND_B) + I2HandPawn(HAND_W) + PopuCount(bb);
+  CheckNum( pawn );
+    
+  BBOr( bb, BB_BLANCE, BB_WLANCE );
+  BBOr( bb, BB_BPRO_LANCE, bb );
+  BBOr( bb, BB_WPRO_LANCE, bb );
+  nlance = I2HandLance(HAND_B) + I2HandLance(HAND_W) + PopuCount(bb);
+  CheckNum( lance );
+
+  BBOr( bb, BB_BKNIGHT, BB_WKNIGHT );
+  BBOr( bb, BB_BPRO_KNIGHT, bb );
+  BBOr( bb, BB_WPRO_KNIGHT, bb );
+  nknight = I2HandKnight(HAND_B) + I2HandKnight(HAND_W) + PopuCount(bb);
+  CheckNum( knight );
+
+  BBOr( bb, BB_BSILVER, BB_WSILVER );
+  BBOr( bb, BB_BPRO_SILVER, bb );
+  BBOr( bb, BB_WPRO_SILVER, bb );
+  nsilver = I2HandSilver(HAND_B) + I2HandSilver(HAND_W) + PopuCount(bb);
+  CheckNum( silver );
+
+  BBOr( bb, BB_BGOLD, BB_WGOLD );
+  ngold = I2HandGold(HAND_B) + I2HandGold(HAND_W) + PopuCount(bb);
+  CheckNum( gold );
+
+  BBOr( bb, BB_BBISHOP, BB_WBISHOP );
+  BBOr( bb, bb, BB_BHORSE );
+  BBOr( bb, bb, BB_WHORSE );
+  nbishop = I2HandBishop(HAND_B) + I2HandBishop(HAND_W) + PopuCount(bb);
+  CheckNum( bishop );
+
+  BBOr( bb, BB_BROOK, BB_WROOK );
+  BBOr( bb, bb, BB_BDRAGON );
+  BBOr( bb, bb, BB_WDRAGON );
+  nrook = I2HandRook(HAND_B) + I2HandRook(HAND_W) + PopuCount(bb);
+  CheckNum( rook );
+
+
+  /* consistency of redundant bitboards */
+  BBOr( bb, BB_BGOLD, BB_BPRO_PAWN );
+  BBOr( bb, bb, BB_BPRO_LANCE );
+  BBOr( bb, bb, BB_BPRO_KNIGHT );
+  BBOr( bb, bb, BB_BPRO_SILVER );
+  if ( BBCmp( bb, BB_BTGOLD ) ) { DOut( "BB_BTGOLD" ); }
+
+  BBOr( bb, BB_BBISHOP, BB_BHORSE );
+  if ( BBCmp( bb, BB_B_BH ) ) { DOut( "BB_B_BH" ); }
+
+  BBOr( bb, BB_BROOK, BB_BDRAGON );
+  if ( BBCmp( bb, BB_B_RD ) ) { DOut( "BB_B_RD" ); }
+
+  BBOr( bb, BB_BHORSE, BB_BDRAGON );
+  BBOr( bb, BB_BKING, bb );
+  if ( BBCmp( bb, BB_B_HDK ) ) { DOut( "BB_B_HDK" ); }
+
+  bb.p[0]  = ( BB_BPAWN.p[0] <<  9 ) & 0x7ffffffU;
+  bb.p[0] |= ( BB_BPAWN.p[1] >> 18 ) & 0x00001ffU;
+  bb.p[1]  = ( BB_BPAWN.p[1] <<  9 ) & 0x7ffffffU;
+  bb.p[1] |= ( BB_BPAWN.p[2] >> 18 ) & 0x00001ffU;
+  bb.p[2]  = ( BB_BPAWN.p[2] <<  9 ) & 0x7ffffffU;
+  if ( BBCmp( bb, BB_BPAWN_ATK ) ) { DOut( "BB_BPAWN_ATK" ); }
+
+  BBOr( bb, BB_BPAWN, BB_BLANCE );
+  BBOr( bb, bb, BB_BKNIGHT );
+  BBOr( bb, bb, BB_BSILVER );
+  BBOr( bb, bb, BB_BTGOLD );
+  BBOr( bb, bb, BB_BBISHOP );
+  BBOr( bb, bb, BB_BROOK );
+  BBOr( bb, bb, BB_B_HDK );
+  if ( BBCmp( bb, BB_BOCCUPY ) ) { DOut( "BB_BOCCUPY" ); }
+      
+  BBOr( bb, BB_WPRO_PAWN, BB_WGOLD );
+  BBOr( bb, BB_WPRO_LANCE, bb );
+  BBOr( bb, BB_WPRO_KNIGHT, bb );
+  BBOr( bb, BB_WPRO_SILVER, bb );
+  if ( BBCmp( bb, BB_WTGOLD ) ) { DOut( "BB_WTGOLD" ); }
+
+  BBOr( bb, BB_WBISHOP, BB_WHORSE );
+  if ( BBCmp( bb, BB_W_BH ) ) { DOut( "BB_W_BH" ); }
+
+  BBOr( bb, BB_WROOK, BB_WDRAGON );
+  if ( BBCmp( bb, BB_W_RD ) ) { DOut( "BB_W_RD" ); }
+
+  BBOr( bb, BB_WHORSE, BB_WDRAGON );
+  BBOr( bb, BB_WKING, bb );
+  if ( BBCmp( bb, BB_W_HDK ) ) { DOut( "BB_W_HDK" ); }
+
+  bb.p[2]  = ( BB_WPAWN.p[2] >>  9 );
+  bb.p[2] |= ( BB_WPAWN.p[1] << 18 ) & 0x7fc0000U;
+  bb.p[1]  = ( BB_WPAWN.p[1] >>  9 );
+  bb.p[1] |= ( BB_WPAWN.p[0] << 18 ) & 0x7fc0000U;
+  bb.p[0]  = ( BB_WPAWN.p[0] >>  9 );
+  if ( BBCmp( bb, BB_WPAWN_ATK ) ) { DOut( "BB_WPAWN_ATK" ); }
+
+  BBOr( bb, BB_WPAWN, BB_WLANCE );
+  BBOr( bb, BB_WKNIGHT, bb );
+  BBOr( bb, BB_WSILVER, bb );
+  BBOr( bb, BB_WTGOLD, bb );
+  BBOr( bb, BB_WBISHOP, bb );
+  BBOr( bb, BB_WROOK, bb );
+  BBOr( bb, BB_W_HDK, bb );
+  if ( BBCmp( bb, BB_WOCCUPY ) ) { DOut( "BB_WOCCUPY" ); }
+      
+  /* consistency of board-array */
+  CheckBoard( PAWN,        pawn );
+  CheckBoard( LANCE,       lance );
+  CheckBoard( KNIGHT,      knight );
+  CheckBoard( SILVER,      silver );
+  CheckBoard( GOLD,        gold );
+  CheckBoard( BISHOP,      bishop );
+  CheckBoard( ROOK,        rook );
+  CheckBoard( KING,        king );
+  CheckBoard( PRO_PAWN,    pro_pawn );
+  CheckBoard( PRO_LANCE,   pro_lance );
+  CheckBoard( PRO_KNIGHT,  pro_knight );
+  CheckBoard( PRO_SILVER,  pro_silver );
+  CheckBoard( HORSE,       horse );
+  CheckBoard( DRAGON,      dragon );
+
+  for ( sq = npiece = 0; sq < nsquare; sq++ )
+    {
+      if ( BOARD[sq] ) { npiece++; }
+    }
+  if ( npiece != PopuCount( OCCUPIED_FILE ) )  { DOut( "OCCUPIED_FILE" ); }
+  if ( npiece != PopuCount( OCCUPIED_DIAG2 ) ) { DOut( "OCCUPIED_DIAG2" ); }
+  if ( npiece != PopuCount( OCCUPIED_DIAG1 ) ) { DOut( "OCCUPIED_DIAG1" ); }
+
+
+  /* Material and Hash signature */
+  mate = eval_material( ptree );
+  if ( mate != MATERIAL ) { DOut( "value of material" ); }
+
+  hk = hash_func( ptree );
+  if ( hk != HASH_KEY  ) { DOut( "hash signature" ); }
+
+  if ( BOARD[SQ_BKING] !=  king ) { DOut( "SQ_BKING" ); }
+  if ( BOARD[SQ_WKING] != -king ) { DOut( "SQ_WKING" ); }
+
+  return 1;
+}
+
+#  undef DOut
+#  undef CheckNum
+#  undef CheckBoard
+
+#endif  /* no NDEBUG */
diff --git a/dek.c b/dek.c
new file mode 100644 (file)
index 0000000..b3464ac
--- /dev/null
+++ b/dek.c
@@ -0,0 +1,314 @@
+#include <string.h>
+#include <stdarg.h>
+#include "shogi.h"
+
+#if defined(DEKUNOBOU)
+
+int
+dek_start( const char *str_addr, int port_dek, int port_bnz )
+{
+  SOCKADDR_IN service;
+  WSADATA wsaData;
+  u_short dek_ns_bnz;
+
+  /* initialize winsock */
+  if ( WSAStartup( MAKEWORD(1,1), &wsaData ) )
+    {
+      str_error = "WSAStartup() failed.";
+      return -2;
+    }
+
+  dek_ul_addr = inet_addr( str_addr );
+  if ( dek_ul_addr == INADDR_NONE )
+    {
+      struct hostent *phe = gethostbyname( str_addr );
+      if ( ! phe )
+       {
+         str_error = str_WSAError( "gethostbyname() faild." );
+         return -2;
+       }
+      dek_ul_addr = *( (u_long *)phe->h_addr_list[0] );
+    }
+
+  dek_ns      = htons( (u_short)port_dek );
+  dek_ns_bnz  = htons( (u_short)port_bnz );
+
+  dek_socket_in = socket( AF_INET, SOCK_STREAM, 0 );
+  if ( dek_socket_in == INVALID_SOCKET )
+    {
+      str_error = str_WSAError( "socket() failed." );
+      return -2;
+    }
+  
+  service.sin_family      = AF_INET;
+  service.sin_addr.s_addr = dek_ul_addr;
+  service.sin_port        = dek_ns_bnz;
+  if ( bind( dek_socket_in, (SOCKADDR *)&service, sizeof(service) )
+       == SOCKET_ERROR )
+    {
+      str_error = "bind() failed.";
+      return -2;
+    }
+
+  if ( listen( dek_socket_in, 1 ) == SOCKET_ERROR )
+    {
+      str_error = "listen() failed.";
+      return -2;
+    }
+
+  dek_s_accept = (SOCKET)SOCKET_ERROR;
+
+  return 1;
+}
+
+
+int
+dek_next_game( tree_t * restrict ptree )
+{
+  if ( dek_ngame != 1 && dek_turn )
+    {
+      Out( "take a nap ..." );
+      Sleep( 37000 );
+      Out( " done\n" );
+    }
+
+  if ( ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL ) < 0
+       || get_elapsed( &time_turn_start ) < 0
+       || ( dek_turn && com_turn_start( ptree, 0 ) < 0 ) ) { return -1; }
+
+  dek_turn  ^= 1;
+  dek_ngame += 1;
+
+  return 1;
+}
+
+
+int
+dek_check( void )
+{
+  struct timeval tv;
+  fd_set readfds;
+  int iret;
+  char ch;
+
+  tv.tv_sec = tv.tv_usec = 0;
+
+  if ( dek_s_accept == SOCKET_ERROR )
+    {
+      FD_ZERO( &readfds );
+#if defined(_MSC_VER)
+#  pragma warning(disable:4127)
+#endif
+      FD_SET( dek_socket_in, &readfds );
+#if defined(_MSC_VER)
+#  pragma warning(default:4127)
+#endif
+      iret = select( 1, &readfds, NULL, NULL, &tv );
+      if ( iret == SOCKET_ERROR )
+       {
+         snprintf( str_message, SIZE_MESSAGE,
+                   "select() with a socket listening failed:%d",
+                  WSAGetLastError() );
+         str_error = str_message;
+         return -1;
+       
+       }
+      if ( ! iret ) { return 0; } /* no connection is pending. */
+
+      dek_s_accept = accept( dek_socket_in, NULL, NULL );
+      if ( dek_s_accept == SOCKET_ERROR )
+       {
+         snprintf( str_message, SIZE_MESSAGE,
+                   "accept() following select() failed:%d",
+                  WSAGetLastError() );
+         str_error = str_message;
+         return -1;
+       }
+    }
+
+  FD_ZERO( &readfds );
+#if defined(_MSC_VER)
+#  pragma warning(disable:4127)
+#endif
+  FD_SET( dek_s_accept, &readfds );
+#if defined(_MSC_VER)
+#  pragma warning(default:4127)
+#endif
+
+  iret = select( 0, &readfds, NULL, NULL, &tv );
+  if ( iret == SOCKET_ERROR )
+    {
+      snprintf( str_message, SIZE_MESSAGE,
+               "select() with a socket accepted failed:%d",
+               WSAGetLastError() );
+      str_error = str_message;
+      return -1;
+    }
+  if ( ! iret ) { return 0; } /* the connection isn't closed,
+                                nor has available data. */
+
+  iret = recv( dek_s_accept, &ch, 1, MSG_PEEK );
+  if ( iret == SOCKET_ERROR )
+    {
+      closesocket( dek_s_accept );
+      dek_s_accept = (SOCKET)SOCKET_ERROR;
+      snprintf( str_message, SIZE_MESSAGE,
+               "recv() with flag MSG_PEEK failed:%d",
+               WSAGetLastError() );
+      str_error = str_message;
+      return -1;
+    }
+  if ( ! iret )
+    {
+      if ( closesocket( dek_s_accept ) )
+       {
+         dek_s_accept = (SOCKET)SOCKET_ERROR;
+         snprintf( str_message, SIZE_MESSAGE,
+                   "closesocket() failed:%d", WSAGetLastError() );
+         str_error = str_message;
+         return -1;
+       }
+      dek_s_accept = (SOCKET)SOCKET_ERROR;
+      return 0; /* the connection has been closed. */
+    }
+
+  return 1; /* data is available for reading. */
+}
+
+
+int
+dek_in( char *str, int n )
+{
+#if defined(_MSC_VER)
+#  pragma warning(disable:4127)
+#endif
+  int count_byte;
+
+  for (;;) {
+    if ( dek_s_accept == SOCKET_ERROR )
+      {
+       Out( "\nwait for new connection...\n" );
+       dek_s_accept = accept( dek_socket_in, NULL, NULL );
+       if ( dek_s_accept == SOCKET_ERROR )
+         {
+           str_error = str_WSAError( "accept() failed." );
+           return -1;
+         }
+      }
+  
+    count_byte = recv( dek_s_accept, str, n, 0 );
+    if ( count_byte == SOCKET_ERROR )
+      {
+       closesocket( dek_s_accept );
+       dek_s_accept = (SOCKET)SOCKET_ERROR;
+       str_error = str_WSAError( "recv() failed." );
+       return -1;
+      }
+    if ( count_byte ) { break; }
+
+    if ( closesocket( dek_s_accept ) )
+      {
+       dek_s_accept = (SOCKET)SOCKET_ERROR;
+       str_error = str_WSAError( "closesocket() failed." );
+       return -1;
+      }
+    dek_s_accept = (SOCKET)SOCKET_ERROR;
+  }
+
+  *( str + count_byte ) = '\0';
+  Out( "recieved %s", str );
+
+  return count_byte;
+#if defined(_MSC_VER)
+#  pragma warning(default:4127)
+#endif
+}
+
+
+int
+dek_out( const char *format, ... )
+{
+  SOCKADDR_IN service;
+  SOCKET socket_out;
+  int nch, iret;
+  char buf[256];
+  va_list arg;
+
+  va_start( arg, format );
+  nch = vsnprintf( buf, 256, format, arg );
+  va_end( arg );
+
+  Out( "send %s", buf );
+
+  socket_out = socket( AF_INET, SOCK_STREAM, 0 );
+  if ( socket_out == INVALID_SOCKET )
+    {
+      snprintf( str_message, SIZE_MESSAGE,
+               "socket() failed:%d", WSAGetLastError() );
+      str_error = str_message;
+      return -2;
+    }
+
+  service.sin_family      = AF_INET;
+  service.sin_addr.s_addr = dek_ul_addr;
+  service.sin_port        = dek_ns;
+  if ( connect( socket_out, (SOCKADDR *)&service, sizeof(service) )
+       == SOCKET_ERROR )
+    {
+      snprintf( str_message, SIZE_MESSAGE,
+               "connect() failed:%d", WSAGetLastError() );
+      str_error = str_message;
+      return -2;
+    }
+
+  iret = send( socket_out, buf, nch, 0 );
+  if ( iret == SOCKET_ERROR )
+    {
+      closesocket( socket_out );
+      snprintf( str_message, SIZE_MESSAGE,
+               "send() failed:%d", WSAGetLastError() );
+      str_error = str_message;
+      return -2;
+    }
+  if ( iret != nch )
+    {
+      closesocket( socket_out );
+      str_error = "send() wrote partial number of bytes.";
+      return -2;
+    }
+
+  if ( closesocket( socket_out ) )
+    {
+      snprintf( str_message, SIZE_MESSAGE,
+               "closesocket() failed:%d", WSAGetLastError() );
+      str_error = str_message;
+      return -2;
+    }
+
+  return 1;
+}
+
+int
+dek_parse( char *str, int len )
+{
+  if ( *str == '+' || *str == '-' )
+    {
+      memmove( str, str+1, 6 );
+      str[6] = '\0';
+    }
+  else if ( ! strcmp( str, str_resign ) )
+    {
+      strncpy( str, "resign", len-1 );
+      str[len-1] = '\0';
+      dek_win += 1;
+      Out( "Bonanza won against Dekunobou\n" );
+    }
+  else {
+    str_error = "unknown command is recieved from Deknobou.";
+    return -2;
+  }
+
+  return 1;
+}
+
+#  endif /* DEKUNOBOU */
diff --git a/evaldiff.c b/evaldiff.c
new file mode 100644 (file)
index 0000000..c43e4fe
--- /dev/null
@@ -0,0 +1,216 @@
+#include <assert.h>
+#include "shogi.h"
+
+void
+check_futile_score_quies( const tree_t * restrict ptree, unsigned int move,
+                         int old_val, int new_val, int turn )
+{
+  const int ifrom = I2From(move);
+  int fsp, fmt, ipc_cap;
+
+  if ( I2PieceMove(move) == king )
+    {
+      fmt = new_val;
+      fsp = new_val - old_val;
+
+      if ( turn )
+       {
+         fmt     += MATERIAL;
+         ipc_cap  = -(int)UToCap(move);
+       }
+      else {
+       fmt     -= MATERIAL;
+       ipc_cap  = (int)UToCap(move);
+      }
+
+      if ( ipc_cap )
+       {
+         fmt -= p_value_ex[15+ipc_cap];
+         fsp -= estimate_score_diff( ptree, move, turn );
+         if ( fsp > fmg_cap_king ) { fmg_cap_king = fsp; }
+       }
+      else if ( fsp > fmg_misc_king ) { fmg_misc_king = fsp; }
+
+      if ( fmt > fmg_mt ) { fmg_mt = fmt; }
+    }
+  else {
+    fsp = new_val - old_val - estimate_score_diff( ptree, move, turn );
+    if ( turn )
+      {
+       fmt     = new_val + MATERIAL;
+       ipc_cap = -(int)UToCap(move);
+      }
+    else {
+      fmt      = new_val - MATERIAL;
+      ipc_cap  = (int)UToCap(move);
+    }
+    if ( ifrom >= nsquare )
+      {
+       if ( fsp > fmg_drop ) { fmg_drop = fsp; }
+      }
+    else {
+      if ( I2IsPromote(move) )
+       {
+         fmt -= benefit2promo[7+I2PieceMove(move)];
+       }
+
+      if ( ipc_cap )
+       {
+         fmt -= p_value_ex[15+ipc_cap];
+         if ( fsp > fmg_cap ) { fmg_cap = fsp; }
+       }
+      else if ( fsp > fmg_misc ) { fmg_misc = fsp; }
+    }
+    
+    if ( fmt > fmg_mt )   { fmg_mt = fmt; }
+  }
+}
+
+
+int
+eval_max_score( const tree_t * restrict ptree, unsigned int move,
+               int stand_pat, int turn, int diff )
+{
+  int score_mt, score_sp, ipc_cap;
+
+  if ( I2From(move) >= nsquare )
+    {
+      score_sp = stand_pat + diff + fmg_drop + FMG_MG;
+      score_mt = ( turn ? -MATERIAL : MATERIAL ) + fmg_mt + FMG_MG_MT;
+    }
+  else {
+    score_sp = diff + stand_pat;
+    score_mt = fmg_mt + FMG_MG_MT;
+    if ( turn )
+      {
+       score_mt -= MATERIAL;
+       ipc_cap   = -(int)UToCap(move);
+      }
+    else {
+      score_mt += MATERIAL;
+      ipc_cap   = (int)UToCap(move);
+    }
+    if ( I2PieceMove(move) == king )
+      {
+       if ( ipc_cap )
+         {
+           score_mt += p_value_ex[15+ipc_cap];
+           score_sp += fmg_cap_king;
+         }
+       else { score_sp += fmg_misc_king; }
+       score_sp += FMG_MG_KING;
+      }
+    else {
+      if ( ipc_cap )
+       {
+         score_mt += p_value_ex[15+ipc_cap];
+         score_sp += fmg_cap;
+       }
+      else { score_sp += fmg_misc; }
+
+      if ( I2IsPromote(move) )
+       {
+         score_mt += benefit2promo[7+I2PieceMove(move)];
+       }
+
+      score_sp += FMG_MG;
+    }
+  }
+  return score_mt < score_sp ? score_mt : score_sp;
+}
+
+
+int
+estimate_score_diff( const tree_t * restrict ptree, unsigned int move,
+                    int turn )
+{
+  const int ibk   = SQ_BKING;
+  const int iwk   = Inv(SQ_WKING);
+  const int ifrom = I2From(move);
+  const int ito   = I2To(move);
+  int diff, ipc_move, ipc_cap, ipro_pc_move;
+
+  if ( I2PieceMove(move) == king )
+    {
+      ipc_cap = (int)UToCap(move);
+      if ( ipc_cap )
+       {
+         diff  = -(int)PcOnSq( ibk, aipos[15+ipc_cap]+ito );
+         diff +=  (int)PcOnSq( iwk, aipos[15-ipc_cap]+Inv(ito) );
+         diff /= FV_SCALE;
+         if ( turn ) { diff -= p_value_ex[15+ipc_cap]; }
+         else        { diff += p_value_ex[15-ipc_cap]; }
+       }
+      else { diff = 0; }
+    }
+  else if ( ifrom >= nsquare )
+    {
+      ipc_move = turn ? -(int)From2Drop(ifrom) : (int)From2Drop(ifrom);
+      diff     = (int)PcOnSq( ibk, aipos[15+ipc_move]+ito );
+      diff    -= (int)PcOnSq( iwk, aipos[15-ipc_move]+Inv(ito) );
+      diff    /= FV_SCALE;
+    }
+  else {
+    if ( turn )
+      {
+       ipc_move     = -(int)I2PieceMove(move);
+       ipc_cap      =  (int)UToCap(move);
+       ipro_pc_move = ipc_move - promote;
+      }
+    else {
+      ipc_move     = (int)I2PieceMove(move);
+      ipc_cap      = -(int)UToCap(move);
+      ipro_pc_move = ipc_move + promote;
+    }
+    if ( I2IsPromote(move) && ipc_cap )
+      {
+       diff  = -(int)PcOnSq( ibk, aipos[15+ipc_move]     + ifrom );
+       diff +=  (int)PcOnSq( ibk, aipos[15+ipro_pc_move] + ito );
+       diff += -(int)PcOnSq( ibk, aipos[15+ipc_cap]      + ito );
+       diff +=  (int)PcOnSq( iwk, aipos[15-ipc_move]     + Inv(ifrom) );
+       diff += -(int)PcOnSq( iwk, aipos[15-ipro_pc_move] + Inv(ito) );
+       diff +=  (int)PcOnSq( iwk, aipos[15-ipc_cap]      + Inv(ito) );
+       diff /= FV_SCALE;
+       if ( turn )
+         {
+           diff -= benefit2promo[7+ipc_move];
+           diff -= p_value_ex[15+ipc_cap];
+         }
+       else {
+         diff += benefit2promo[7+ipc_move];
+         diff += p_value_ex[15+ipc_cap];
+       }
+      }
+    else if ( ipc_cap )
+      {
+       diff  = -(int)PcOnSq( ibk, aipos[15+ipc_move] + ifrom );
+       diff +=  (int)PcOnSq( ibk, aipos[15+ipc_move] + ito );
+       diff += -(int)PcOnSq( ibk, aipos[15+ipc_cap]  + ito );
+       diff +=  (int)PcOnSq( iwk, aipos[15-ipc_move] + Inv(ifrom) );
+       diff += -(int)PcOnSq( iwk, aipos[15-ipc_move] + Inv(ito) );
+       diff +=  (int)PcOnSq( iwk, aipos[15-ipc_cap]  + Inv(ito) );
+       diff /= FV_SCALE;
+       diff += turn ? -p_value_ex[15+ipc_cap] : p_value_ex[15+ipc_cap];
+      }
+    else if ( I2IsPromote(move) )
+      {
+       diff  = -(int)PcOnSq( ibk, aipos[15+ipc_move]     + ifrom );
+       diff +=  (int)PcOnSq( ibk, aipos[15+ipro_pc_move] + ito );
+       diff +=  (int)PcOnSq( iwk, aipos[15-ipc_move]     + Inv(ifrom) );
+       diff += -(int)PcOnSq( iwk, aipos[15-ipro_pc_move] + Inv(ito) );
+       diff /= FV_SCALE;
+       diff += turn ? -benefit2promo[7+ipc_move] : benefit2promo[7+ipc_move];
+      }
+    else {
+      diff  = -(int)PcOnSq( ibk, aipos[15+ipc_move] + ifrom );
+      diff +=  (int)PcOnSq( ibk, aipos[15+ipc_move] + ito );
+      diff +=  (int)PcOnSq( iwk, aipos[15-ipc_move] + Inv(ifrom) );
+      diff += -(int)PcOnSq( iwk, aipos[15-ipc_move] + Inv(ito) );
+      diff /= FV_SCALE;
+    }
+  }
+  
+  if ( turn ) { diff = -diff; }
+
+  return diff;
+}
diff --git a/evaluate.c b/evaluate.c
new file mode 100644 (file)
index 0000000..85b8a63
--- /dev/null
@@ -0,0 +1,494 @@
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "shogi.h"
+
+static int ehash_probe( uint64_t current_key, unsigned int hand_b,
+                       int *pscore );
+static void ehash_store( uint64_t key, unsigned int hand_b, int score );
+static int make_list( const tree_t * restrict ptree, int * restrict pscore,
+                     int list0[52], int list1[52] );
+
+int
+eval_material( const tree_t * restrict ptree )
+{
+  int material, itemp;
+
+  itemp     = PopuCount( BB_BPAWN )   + (int)I2HandPawn( HAND_B );
+  itemp    -= PopuCount( BB_WPAWN )   + (int)I2HandPawn( HAND_W );
+  material  = itemp * p_value[15+pawn];
+
+  itemp     = PopuCount( BB_BLANCE )  + (int)I2HandLance( HAND_B );
+  itemp    -= PopuCount( BB_WLANCE )  + (int)I2HandLance( HAND_W );
+  material += itemp * p_value[15+lance];
+
+  itemp     = PopuCount( BB_BKNIGHT ) + (int)I2HandKnight( HAND_B );
+  itemp    -= PopuCount( BB_WKNIGHT ) + (int)I2HandKnight( HAND_W );
+  material += itemp * p_value[15+knight];
+
+  itemp     = PopuCount( BB_BSILVER ) + (int)I2HandSilver( HAND_B );
+  itemp    -= PopuCount( BB_WSILVER ) + (int)I2HandSilver( HAND_W );
+  material += itemp * p_value[15+silver];
+
+  itemp     = PopuCount( BB_BGOLD )   + (int)I2HandGold( HAND_B );
+  itemp    -= PopuCount( BB_WGOLD )   + (int)I2HandGold( HAND_W );
+  material += itemp * p_value[15+gold];
+
+  itemp     = PopuCount( BB_BBISHOP ) + (int)I2HandBishop( HAND_B );
+  itemp    -= PopuCount( BB_WBISHOP ) + (int)I2HandBishop( HAND_W );
+  material += itemp * p_value[15+bishop];
+
+  itemp     = PopuCount( BB_BROOK )   + (int)I2HandRook( HAND_B );
+  itemp    -= PopuCount( BB_WROOK )   + (int)I2HandRook( HAND_W );
+  material += itemp * p_value[15+rook];
+
+  itemp     = PopuCount( BB_BPRO_PAWN );
+  itemp    -= PopuCount( BB_WPRO_PAWN );
+  material += itemp * p_value[15+pro_pawn];
+
+  itemp     = PopuCount( BB_BPRO_LANCE );
+  itemp    -= PopuCount( BB_WPRO_LANCE );
+  material += itemp * p_value[15+pro_lance];
+
+  itemp     = PopuCount( BB_BPRO_KNIGHT );
+  itemp    -= PopuCount( BB_WPRO_KNIGHT );
+  material += itemp * p_value[15+pro_knight];
+
+  itemp     = PopuCount( BB_BPRO_SILVER );
+  itemp    -= PopuCount( BB_WPRO_SILVER );
+  material += itemp * p_value[15+pro_silver];
+
+  itemp     = PopuCount( BB_BHORSE );
+  itemp    -= PopuCount( BB_WHORSE );
+  material += itemp * p_value[15+horse];
+
+  itemp     = PopuCount( BB_BDRAGON );
+  itemp    -= PopuCount( BB_WDRAGON );
+  material += itemp * p_value[15+dragon];
+
+  return material;
+}
+
+
+int
+evaluate( tree_t * restrict ptree, int ply, int turn )
+{
+  int list0[52], list1[52];
+  int nlist, score, sq_bk, sq_wk, k0, k1, l0, l1, i, j, sum;
+
+  ptree->neval_called++;
+
+  if ( ptree->stand_pat[ply] != score_bound )
+    {
+      return (int)ptree->stand_pat[ply];
+    }
+
+  if ( ehash_probe( HASH_KEY, HAND_B, &score ) )
+    {
+      score                 = turn ? -score : score;
+      ptree->stand_pat[ply] = (short)score;
+
+      return score;
+    }
+
+
+  score = 0;
+  nlist = make_list( ptree, &score, list0, list1 );
+  sq_bk = SQ_BKING;
+  sq_wk = Inv( SQ_WKING );
+
+  sum = 0;
+  for ( i = 0; i < nlist; i++ )
+    {
+      k0 = list0[i];
+      k1 = list1[i];
+      for ( j = 0; j <= i; j++ )
+       {
+         l0 = list0[j];
+         l1 = list1[j];
+         assert( k0 >= l0 && k1 >= l1 );
+         sum += PcPcOnSq( sq_bk, k0, l0 );
+         sum -= PcPcOnSq( sq_wk, k1, l1 );
+       }
+    }
+  
+  score += sum;
+  score /= FV_SCALE;
+
+  score += MATERIAL;
+
+#if defined(MNJ_LAN)
+  if ( sckt_mnj != SCKT_NULL ) { score += mnj_tbl[ HASH_KEY & MNJ_MASK ]; }
+#endif
+
+#if ! defined(MINIMUM)
+  if ( abs(score) > score_max_eval )
+    {
+      out_warning( "A score at evaluate() is out of bounce." );
+    }
+#endif
+
+  ehash_store( HASH_KEY, HAND_B, score );
+
+  score = turn ? -score : score;
+  ptree->stand_pat[ply] = (short)score;
+
+  return score;
+
+}
+
+
+void ehash_clear( void )
+{
+  memset( ehash_tbl, 0, sizeof(ehash_tbl) );
+}
+
+
+static int ehash_probe( uint64_t current_key, unsigned int hand_b,
+                       int *pscore )
+{
+  uint64_t hash_word, hash_key;
+
+  hash_word = ehash_tbl[ (unsigned int)current_key & EHASH_MASK ];
+
+#if ! defined(__x86_64__)
+  hash_word ^= hash_word << 32;
+#endif
+
+  current_key ^= (uint64_t)hand_b << 16;
+  current_key &= ~(uint64_t)0xffffU;
+
+  hash_key  = hash_word;
+  hash_key &= ~(uint64_t)0xffffU;
+
+  if ( hash_key != current_key ) { return 0; }
+
+  *pscore = (int)( (unsigned int)hash_word & 0xffffU ) - 32768;
+
+  return 1;
+}
+
+
+static void ehash_store( uint64_t key, unsigned int hand_b, int score )
+{
+  uint64_t hash_word;
+
+  hash_word  = key;
+  hash_word ^= (uint64_t)hand_b << 16;
+  hash_word &= ~(uint64_t)0xffffU;
+  hash_word |= (uint64_t)( score + 32768 );
+
+#if ! defined(__x86_64__)
+  hash_word ^= hash_word << 32;
+#endif
+
+  ehash_tbl[ (unsigned int)key & EHASH_MASK ] = hash_word;
+}
+
+
+static int
+make_list( const tree_t * restrict ptree, int * restrict pscore,
+          int list0[52], int list1[52] )
+{
+  bitboard_t bb;
+  int list2[34];
+  int nlist, sq, n2, i, score, sq_bk0, sq_wk0, sq_bk1, sq_wk1;
+
+  nlist  = 14;
+  score  = 0;
+  sq_bk0 = SQ_BKING;
+  sq_wk0 = SQ_WKING;
+  sq_bk1 = Inv(SQ_WKING);
+  sq_wk1 = Inv(SQ_BKING);
+
+  list0[ 0] = f_hand_pawn   + I2HandPawn(HAND_B);
+  list0[ 1] = e_hand_pawn   + I2HandPawn(HAND_W);
+  list0[ 2] = f_hand_lance  + I2HandLance(HAND_B);
+  list0[ 3] = e_hand_lance  + I2HandLance(HAND_W);
+  list0[ 4] = f_hand_knight + I2HandKnight(HAND_B);
+  list0[ 5] = e_hand_knight + I2HandKnight(HAND_W);
+  list0[ 6] = f_hand_silver + I2HandSilver(HAND_B);
+  list0[ 7] = e_hand_silver + I2HandSilver(HAND_W);
+  list0[ 8] = f_hand_gold   + I2HandGold(HAND_B);
+  list0[ 9] = e_hand_gold   + I2HandGold(HAND_W);
+  list0[10] = f_hand_bishop + I2HandBishop(HAND_B);
+  list0[11] = e_hand_bishop + I2HandBishop(HAND_W);
+  list0[12] = f_hand_rook   + I2HandRook(HAND_B);
+  list0[13] = e_hand_rook   + I2HandRook(HAND_W);
+
+  list1[ 0] = f_hand_pawn   + I2HandPawn(HAND_W);
+  list1[ 1] = e_hand_pawn   + I2HandPawn(HAND_B);
+  list1[ 2] = f_hand_lance  + I2HandLance(HAND_W);
+  list1[ 3] = e_hand_lance  + I2HandLance(HAND_B);
+  list1[ 4] = f_hand_knight + I2HandKnight(HAND_W);
+  list1[ 5] = e_hand_knight + I2HandKnight(HAND_B);
+  list1[ 6] = f_hand_silver + I2HandSilver(HAND_W);
+  list1[ 7] = e_hand_silver + I2HandSilver(HAND_B);
+  list1[ 8] = f_hand_gold   + I2HandGold(HAND_W);
+  list1[ 9] = e_hand_gold   + I2HandGold(HAND_B);
+  list1[10] = f_hand_bishop + I2HandBishop(HAND_W);
+  list1[11] = e_hand_bishop + I2HandBishop(HAND_B);
+  list1[12] = f_hand_rook   + I2HandRook(HAND_W);
+  list1[13] = e_hand_rook   + I2HandRook(HAND_B);
+
+  score += kkp[sq_bk0][sq_wk0][ kkp_hand_pawn   + I2HandPawn(HAND_B) ];
+  score += kkp[sq_bk0][sq_wk0][ kkp_hand_lance  + I2HandLance(HAND_B) ];
+  score += kkp[sq_bk0][sq_wk0][ kkp_hand_knight + I2HandKnight(HAND_B) ];
+  score += kkp[sq_bk0][sq_wk0][ kkp_hand_silver + I2HandSilver(HAND_B) ];
+  score += kkp[sq_bk0][sq_wk0][ kkp_hand_gold   + I2HandGold(HAND_B) ];
+  score += kkp[sq_bk0][sq_wk0][ kkp_hand_bishop + I2HandBishop(HAND_B) ];
+  score += kkp[sq_bk0][sq_wk0][ kkp_hand_rook   + I2HandRook(HAND_B) ];
+
+  score -= kkp[sq_bk1][sq_wk1][ kkp_hand_pawn   + I2HandPawn(HAND_W) ];
+  score -= kkp[sq_bk1][sq_wk1][ kkp_hand_lance  + I2HandLance(HAND_W) ];
+  score -= kkp[sq_bk1][sq_wk1][ kkp_hand_knight + I2HandKnight(HAND_W) ];
+  score -= kkp[sq_bk1][sq_wk1][ kkp_hand_silver + I2HandSilver(HAND_W) ];
+  score -= kkp[sq_bk1][sq_wk1][ kkp_hand_gold   + I2HandGold(HAND_W) ];
+  score -= kkp[sq_bk1][sq_wk1][ kkp_hand_bishop + I2HandBishop(HAND_W) ];
+  score -= kkp[sq_bk1][sq_wk1][ kkp_hand_rook   + I2HandRook(HAND_W) ];
+
+  n2 = 0;
+  bb = BB_BPAWN;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_pawn + sq;
+    list2[n2]    = e_pawn + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_pawn + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WPAWN;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_pawn + sq;
+    list2[n2]    = f_pawn + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_pawn + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+  n2 = 0;
+  bb = BB_BLANCE;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_lance + sq;
+    list2[n2]    = e_lance + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_lance + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WLANCE;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_lance + sq;
+    list2[n2]    = f_lance + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_lance + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BKNIGHT;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_knight + sq;
+    list2[n2]    = e_knight + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_knight + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WKNIGHT;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_knight + sq;
+    list2[n2]    = f_knight + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_knight + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BSILVER;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_silver + sq;
+    list2[n2]    = e_silver + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_silver + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WSILVER;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_silver + sq;
+    list2[n2]    = f_silver + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_silver + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BTGOLD;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_gold + sq;
+    list2[n2]    = e_gold + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_gold + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WTGOLD;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_gold + sq;
+    list2[n2]    = f_gold + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_gold + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BBISHOP;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_bishop + sq;
+    list2[n2]    = e_bishop + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_bishop + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WBISHOP;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_bishop + sq;
+    list2[n2]    = f_bishop + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_bishop + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BHORSE;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_horse + sq;
+    list2[n2]    = e_horse + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_horse + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WHORSE;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_horse + sq;
+    list2[n2]    = f_horse + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_horse + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BROOK;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_rook + sq;
+    list2[n2]    = e_rook + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_rook + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WROOK;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_rook + sq;
+    list2[n2]    = f_rook + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_rook + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BDRAGON;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = f_dragon + sq;
+    list2[n2]    = e_dragon + Inv(sq);
+    score += kkp[sq_bk0][sq_wk0][ kkp_dragon + sq ];
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WDRAGON;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    list0[nlist] = e_dragon + sq;
+    list2[n2]    = f_dragon + Inv(sq);
+    score -= kkp[sq_bk1][sq_wk1][ kkp_dragon + Inv(sq) ];
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+  assert( nlist <= 52 );
+  *pscore += score;
+  return nlist;
+}
diff --git a/gencap.c b/gencap.c
new file mode 100644 (file)
index 0000000..06ba52b
--- /dev/null
+++ b/gencap.c
@@ -0,0 +1,460 @@
+#include "shogi.h"
+
+unsigned int *
+b_gen_captures( const tree_t * restrict ptree, unsigned int * restrict pmove )
+{
+  bitboard_t bb_movable, bb_capture, bb_piece, bb_desti;
+  unsigned int utemp;
+  int ito, ifrom;
+
+  bb_capture = BB_WOCCUPY;
+  BBNot( bb_movable, BB_BOCCUPY );
+
+  bb_desti.p[0] = BB_BPAWN_ATK.p[0] & bb_movable.p[0];
+  bb_desti.p[1] = BB_BPAWN_ATK.p[1] & bb_capture.p[1];
+  bb_desti.p[2] = BB_BPAWN_ATK.p[2] & bb_capture.p[2];
+  while ( BBToU( bb_desti ) )
+    {
+      ito = LastOne( bb_desti );
+      Xor( ito, bb_desti );
+
+      ifrom = ito + 9;
+      utemp = ( To2Move(ito) | From2Move(ifrom) | Cap2Move(-BOARD[ito])
+               | Piece2Move(pawn) );
+      if ( ito < A6 ) { utemp |= FLAG_PROMO; }
+      *pmove++ = utemp;
+    }
+
+  bb_piece = BB_BSILVER;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = LastOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      BBAnd( bb_desti, bb_capture, abb_b_silver_attacks[ifrom] );
+      while ( BBToU( bb_desti ) )
+       {
+         ito = LastOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom) | Cap2Move(-BOARD[ito])
+                   | Piece2Move(silver) );
+         if ( ito < A6 || ifrom < A6 ) { *pmove++ = utemp | FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_BTGOLD;
+  while( BBToU( bb_piece ) )
+    {
+      ifrom = LastOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      BBAnd( bb_desti, bb_capture, abb_b_gold_attacks[ifrom] );
+      while ( BBToU( bb_desti ) )
+       {
+         ito = LastOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         *pmove++ = ( To2Move(ito) | From2Move(ifrom)
+                      | Cap2Move(-BOARD[ito])
+                      | Piece2Move(BOARD[ifrom]) );
+       }
+    }
+
+  ifrom = SQ_BKING;
+  BBAnd( bb_desti, bb_capture, abb_king_attacks[ifrom] );
+  while ( BBToU( bb_desti ) )
+    {
+      ito = LastOne( bb_desti );
+      Xor( ito, bb_desti );
+
+      *pmove++ = ( To2Move(ito) | From2Move(ifrom)
+                  | Cap2Move(-BOARD[ito]) | Piece2Move(king) );
+    }
+
+  bb_piece = BB_BBISHOP;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = LastOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      AttackBishop( bb_desti, ifrom );
+      bb_desti.p[0] &= bb_movable.p[0];
+      if ( ifrom < A6 )
+       {
+         bb_desti.p[1] &= bb_movable.p[1];
+         bb_desti.p[2] &= bb_movable.p[2];
+       }
+      else {
+       bb_desti.p[1] &= bb_capture.p[1];
+       bb_desti.p[2] &= bb_capture.p[2];
+      }
+
+      while ( BBToU( bb_desti ) )
+       {
+         ito = LastOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom)
+                   | Cap2Move(-BOARD[ito]) | Piece2Move(bishop) );
+         if ( ito < A6 || ifrom < A6 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_BROOK;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = LastOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      AttackRook( bb_desti, ifrom );
+      bb_desti.p[0] &= bb_movable.p[0];
+      if ( ifrom < A6 )
+       {
+         bb_desti.p[1] &= bb_movable.p[1];
+         bb_desti.p[2] &= bb_movable.p[2];
+       }
+      else {
+       bb_desti.p[1] &= bb_capture.p[1];
+       bb_desti.p[2] &= bb_capture.p[2];
+      }
+
+      while ( BBToU( bb_desti ) )
+       {
+         ito = LastOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom)
+                   | Cap2Move(-BOARD[ito]) | Piece2Move(rook) );
+         if ( ito < A6 || ifrom < A6 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_BHORSE;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = LastOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      AttackHorse( bb_desti, ifrom );
+      BBAnd( bb_desti, bb_desti, bb_capture );
+      while ( BBToU( bb_desti ) )
+       {
+         ito = LastOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         *pmove++ = ( To2Move(ito) | From2Move(ifrom)
+                      | Cap2Move(-BOARD[ito]) | Piece2Move(horse) );
+       }
+    }
+
+  bb_piece = BB_BDRAGON;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = LastOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      AttackDragon( bb_desti, ifrom );
+      BBAnd( bb_desti, bb_desti, bb_capture );
+      while ( BBToU( bb_desti ) )
+       {
+         ito = LastOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         *pmove++ = ( To2Move(ito) | From2Move(ifrom)
+                      | Cap2Move(-BOARD[ito]) | Piece2Move(dragon) );
+       }
+    }
+
+  bb_piece = BB_BLANCE;
+  while( BBToU( bb_piece ) )
+    {
+      ifrom = LastOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      bb_desti = AttackFile( ifrom );
+      BBAnd( bb_desti, bb_desti, abb_minus_rays[ifrom] );
+      bb_desti.p[0] &= bb_movable.p[0];
+      bb_desti.p[1] &= bb_capture.p[1];
+      bb_desti.p[2] &= bb_capture.p[2];
+
+      while ( BBToU( bb_desti ) )
+       {
+         ito = LastOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom)
+                   | Cap2Move(-BOARD[ito]) | Piece2Move(lance) );
+         if      ( ito < A7 ) { *pmove++ = utemp | FLAG_PROMO; }
+         else if ( ito < A6 )
+           {
+             *pmove++ = utemp | FLAG_PROMO;
+             if ( UToCap(utemp) ) { *pmove++ = utemp; }
+           }
+         else { *pmove++ = utemp; }
+       }
+    }
+
+  bb_piece = BB_BKNIGHT;
+  while( BBToU( bb_piece ) )
+    {
+      ifrom = LastOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      bb_desti = abb_b_knight_attacks[ifrom];
+      bb_desti.p[0] &= bb_movable.p[0];
+      bb_desti.p[1] &= bb_capture.p[1];
+      bb_desti.p[2] &= bb_capture.p[2];
+
+      while ( BBToU( bb_desti ) )
+       {
+         ito = LastOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom)
+                   | Cap2Move(-BOARD[ito]) | Piece2Move(knight) );
+         if      ( ito < A7 ) { *pmove++ = utemp | FLAG_PROMO; }
+         else if ( ito < A6 )
+           {
+             *pmove++ = utemp | FLAG_PROMO;
+             if ( UToCap(utemp) ) { *pmove++ = utemp; }
+           }
+         else { *pmove++ = utemp; }
+       }
+    }
+
+  return pmove;
+}
+
+
+unsigned int *
+w_gen_captures( const tree_t * restrict ptree, unsigned int * restrict pmove )
+{
+  bitboard_t bb_movable, bb_capture, bb_piece, bb_desti;
+  unsigned int utemp;
+  int ito, ifrom;
+
+  bb_capture = BB_BOCCUPY;
+  BBNot( bb_movable, BB_WOCCUPY );
+
+  bb_desti.p[2] = BB_WPAWN_ATK.p[2] & bb_movable.p[2];
+  bb_desti.p[1] = BB_WPAWN_ATK.p[1] & bb_capture.p[1];
+  bb_desti.p[0] = BB_WPAWN_ATK.p[0] & bb_capture.p[0];
+  while ( BBToU( bb_desti ) )
+    {
+      ito = FirstOne( bb_desti );
+      Xor( ito, bb_desti );
+
+      ifrom = ito - 9;
+      utemp = ( To2Move(ito) | From2Move(ifrom) | Cap2Move(BOARD[ito])
+               | Piece2Move(pawn) );
+      if ( ito > I4 ) { utemp |= FLAG_PROMO; }
+      *pmove++ = utemp;
+    }
+
+  bb_piece = BB_WSILVER;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = FirstOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      BBAnd( bb_desti, bb_capture, abb_w_silver_attacks[ifrom] );
+      while ( BBToU( bb_desti ) )
+       {
+         ito = FirstOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom) | Cap2Move(BOARD[ito])
+                   | Piece2Move(silver) );
+         if ( ito > I4 || ifrom > I4 ) { *pmove++ = utemp | FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_WTGOLD;
+  while( BBToU( bb_piece ) )
+    {
+      ifrom = FirstOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      BBAnd( bb_desti, bb_capture, abb_w_gold_attacks[ifrom] );
+      while ( BBToU( bb_desti ) )
+       {
+         ito = FirstOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         *pmove++ = ( To2Move(ito) | From2Move(ifrom)
+                      | Cap2Move(BOARD[ito])
+                      | Piece2Move(-BOARD[ifrom]) );
+       }
+    }
+
+  ifrom = SQ_WKING;
+  BBAnd( bb_desti, bb_capture, abb_king_attacks[ifrom] );
+  while ( BBToU( bb_desti ) )
+    {
+      ito = FirstOne( bb_desti );
+      Xor( ito, bb_desti );
+
+      *pmove++ = ( To2Move(ito) | From2Move(ifrom)
+                  | Cap2Move(BOARD[ito]) | Piece2Move(king) );
+    }
+
+  bb_piece = BB_WBISHOP;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = FirstOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      AttackBishop( bb_desti, ifrom );
+      bb_desti.p[2] &= bb_movable.p[2];
+      if ( ifrom > I4 )
+       {
+         bb_desti.p[1] &= bb_movable.p[1];
+         bb_desti.p[0] &= bb_movable.p[0];
+       }
+      else {
+       bb_desti.p[1] &= bb_capture.p[1];
+       bb_desti.p[0] &= bb_capture.p[0];
+      }
+
+      while ( BBToU( bb_desti ) )
+       {
+         ito = FirstOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom)
+                   | Cap2Move(BOARD[ito]) | Piece2Move(bishop) );
+         if ( ito > I4 || ifrom > I4 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_WROOK;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = FirstOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      AttackRook( bb_desti, ifrom );
+      bb_desti.p[2] &= bb_movable.p[2];
+      if ( ifrom > I4 )
+       {
+         bb_desti.p[1] &= bb_movable.p[1];
+         bb_desti.p[0] &= bb_movable.p[0];
+       }
+      else {
+       bb_desti.p[1] &= bb_capture.p[1];
+       bb_desti.p[0] &= bb_capture.p[0];
+      }
+
+      while ( BBToU( bb_desti ) )
+       {
+         ito = FirstOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom)
+                   | Cap2Move(BOARD[ito]) | Piece2Move(rook) );
+         if ( ito > I4 || ifrom > I4 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_WHORSE;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = FirstOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      AttackHorse( bb_desti, ifrom );
+      BBAnd( bb_desti, bb_desti, bb_capture );
+      while ( BBToU( bb_desti ) )
+       {
+         ito = FirstOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         *pmove++ = ( To2Move(ito) | From2Move(ifrom)
+                      | Cap2Move(BOARD[ito]) | Piece2Move(horse) );
+       }
+    }
+
+  bb_piece = BB_WDRAGON;
+  while ( BBToU( bb_piece ) )
+    {
+      ifrom = FirstOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      AttackDragon( bb_desti, ifrom );
+      BBAnd( bb_desti, bb_desti, bb_capture );
+      while ( BBToU( bb_desti ) )
+       {
+         ito = FirstOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         *pmove++ = ( To2Move(ito) | From2Move(ifrom)
+                      | Cap2Move(BOARD[ito]) | Piece2Move(dragon) );
+       }
+    }
+
+  bb_piece = BB_WLANCE;
+  while( BBToU( bb_piece ) )
+    {
+      ifrom = FirstOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      bb_desti = AttackFile( ifrom );
+      BBAnd( bb_desti, bb_desti, abb_plus_rays[ifrom] );
+      bb_desti.p[2] &= bb_movable.p[2];
+      bb_desti.p[1] &= bb_capture.p[1];
+      bb_desti.p[0] &= bb_capture.p[0];
+
+      while ( BBToU( bb_desti ) )
+       {
+         ito = FirstOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom)
+                   | Cap2Move(BOARD[ito]) | Piece2Move(lance) );
+         if      ( ito > I3 ) { *pmove++ = utemp | FLAG_PROMO; }
+         else if ( ito > I4 )
+           {
+             *pmove++ = utemp | FLAG_PROMO;
+             if ( UToCap(utemp) ) { *pmove++ = utemp; }
+           }
+         else { *pmove++ = utemp; }
+       }
+    }
+
+  bb_piece = BB_WKNIGHT;
+  while( BBToU( bb_piece ) )
+    {
+      ifrom = FirstOne( bb_piece );
+      Xor( ifrom, bb_piece );
+
+      bb_desti = abb_w_knight_attacks[ifrom];
+      bb_desti.p[2] &= bb_movable.p[2];
+      bb_desti.p[1] &= bb_capture.p[1];
+      bb_desti.p[0] &= bb_capture.p[0];
+
+      while ( BBToU( bb_desti ) )
+       {
+         ito = FirstOne( bb_desti );
+         Xor( ito, bb_desti );
+
+         utemp = ( To2Move(ito) | From2Move(ifrom)
+                   | Cap2Move(BOARD[ito]) | Piece2Move(knight) );
+         if      ( ito > I3 ) { *pmove++ = utemp | FLAG_PROMO; }
+         else if ( ito > I4 )
+           {
+             *pmove++ = utemp | FLAG_PROMO;
+             if ( UToCap(utemp) ) { *pmove++ = utemp; }
+           }
+         else { *pmove++ = utemp; }
+       }
+    }
+
+  return pmove;
+}
diff --git a/genchk.c b/genchk.c
new file mode 100644 (file)
index 0000000..dfefee0
--- /dev/null
+++ b/genchk.c
@@ -0,0 +1,1441 @@
+#include <assert.h>\r
+#include "shogi.h"\r
+\r
+\r
+static bitboard_t add_behind_attacks( int idirec, int ik, bitboard_t bb );\r
+\r
+\r
+unsigned int *\r
+b_gen_checks( tree_t * restrict __ptree__, unsigned int * restrict pmove )\r
+{\r
+  bitboard_t bb_piece, bb_rook_chk, bb_bishop_chk, bb_chk, bb_move_to;\r
+  bitboard_t bb_diag1_chk, bb_diag2_chk, bb_file_chk, bb_drop_to, bb_desti;\r
+  const tree_t * restrict ptree = __ptree__;\r
+  unsigned int u0, u1, u2;\r
+  int from, to, sq_wk, idirec;\r
+\r
+  sq_wk = SQ_WKING;\r
+  bb_rook_chk  = bb_file_chk = AttackFile( sq_wk );\r
+  bb_rook_chk.p[aslide[sq_wk].ir0] |= AttackRank( sq_wk );\r
+  bb_diag1_chk = AttackDiag1( sq_wk );\r
+  bb_diag2_chk = AttackDiag2( sq_wk );\r
+  BBOr( bb_bishop_chk, bb_diag1_chk, bb_diag2_chk );\r
+  BBNot( bb_move_to, BB_BOCCUPY );\r
+  BBOr( bb_drop_to, BB_BOCCUPY, BB_WOCCUPY );\r
+  BBNot( bb_drop_to, bb_drop_to );\r
+\r
+  from  = SQ_BKING;\r
+  idirec = (int)adirec[sq_wk][from];\r
+  if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+    {\r
+      BBIni( bb_chk );\r
+      bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+      BBAnd( bb_chk, bb_chk, abb_king_attacks[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(king)\r
+           | Cap2Move(-BOARD[to]);\r
+       }\r
+    }\r
+\r
+\r
+  bb_piece = BB_BDRAGON;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = LastOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      BBOr( bb_chk, bb_rook_chk, abb_king_attacks[sq_wk] );\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      AttackDragon( bb_desti, from );\r
+      BBAnd( bb_chk, bb_chk, bb_desti );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(dragon)\r
+           | Cap2Move(-BOARD[to]);\r
+       }\r
+    }\r
+\r
+  bb_piece = BB_BHORSE;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = LastOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      BBOr( bb_chk, bb_bishop_chk, abb_king_attacks[sq_wk] );\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      AttackHorse( bb_desti, from );\r
+      BBAnd( bb_chk, bb_chk, bb_desti );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(horse)\r
+           | Cap2Move(-BOARD[to]);\r
+       }\r
+    }\r
+\r
+  u1 = BB_BROOK.p[1];\r
+  u2 = BB_BROOK.p[2];\r
+  while( u1 | u2 )\r
+    {\r
+      from = last_one12( u1, u2 );\r
+      u1   ^= abb_mask[from].p[1];\r
+      u2   ^= abb_mask[from].p[2];\r
+\r
+      AttackRook( bb_desti, from );\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         BBAnd( bb_chk, bb_desti, bb_move_to );\r
+       }\r
+      else {\r
+       bb_chk       = bb_rook_chk;\r
+       bb_chk.p[0] |= abb_king_attacks[sq_wk].p[0];\r
+       BBAnd( bb_chk, bb_chk, bb_desti );\r
+       BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      }\r
+\r
+      while ( bb_chk.p[0] )\r
+       {\r
+         to          = last_one0( bb_chk.p[0] );\r
+         bb_chk.p[0] ^= abb_mask[to].p[0];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(rook)\r
+           | Cap2Move(-BOARD[to]) | FLAG_PROMO;\r
+       }\r
+\r
+      while( bb_chk.p[1] | bb_chk.p[2] )\r
+       {\r
+         to          = last_one12( bb_chk.p[1], bb_chk.p[2] );\r
+         bb_chk.p[1] ^= abb_mask[to].p[1];\r
+         bb_chk.p[2] ^= abb_mask[to].p[2];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(rook)\r
+           | Cap2Move(-BOARD[to]);\r
+       }\r
+    }\r
+\r
+  u0 = BB_BROOK.p[0];\r
+  while( u0 )\r
+    {\r
+      from = last_one0( u0 );\r
+      u0   ^= abb_mask[from].p[0];\r
+      \r
+      AttackRook( bb_desti, from );\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         BBAnd( bb_chk, bb_desti, bb_move_to );\r
+       }\r
+      else {\r
+       BBOr( bb_chk, bb_rook_chk, abb_king_attacks[sq_wk] );\r
+       BBAnd( bb_chk, bb_chk, bb_desti );\r
+       BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      }\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(rook)\r
+           | Cap2Move(-BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+\r
+  u1 = BB_BBISHOP.p[1];\r
+  u2 = BB_BBISHOP.p[2];\r
+  while( u1 | u2 )\r
+    {\r
+      from = last_one12( u1, u2 );\r
+      u1   ^= abb_mask[from].p[1];\r
+      u2   ^= abb_mask[from].p[2];\r
+\r
+      AttackBishop( bb_desti, from );\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         BBAnd( bb_chk, bb_desti, bb_move_to );\r
+       }\r
+      else {\r
+       bb_chk       = bb_bishop_chk;\r
+       bb_chk.p[0] |= abb_king_attacks[sq_wk].p[0];\r
+       BBAnd( bb_chk, bb_chk, bb_desti );\r
+       BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      }\r
+\r
+      while ( bb_chk.p[0] )\r
+       {\r
+         to          = last_one0( bb_chk.p[0] );\r
+         bb_chk.p[0] ^= abb_mask[to].p[0];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(bishop)\r
+           | Cap2Move(-BOARD[to]) | FLAG_PROMO;\r
+       }\r
+\r
+      while( bb_chk.p[1] | bb_chk.p[2] )\r
+       {\r
+         to          = last_one12( bb_chk.p[1], bb_chk.p[2] );\r
+         bb_chk.p[1] ^= abb_mask[to].p[1];\r
+         bb_chk.p[2] ^= abb_mask[to].p[2];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(bishop)\r
+           | Cap2Move(-BOARD[to]);\r
+       }\r
+    }\r
+\r
+  u0 = BB_BBISHOP.p[0];\r
+  while( u0 )\r
+    {\r
+      from = last_one0( u0 );\r
+      u0   ^= abb_mask[from].p[0];\r
+      \r
+      AttackBishop( bb_desti, from );\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         BBAnd( bb_chk, bb_desti, bb_move_to );\r
+       }\r
+      else {\r
+       BBOr( bb_chk, bb_bishop_chk, abb_king_attacks[sq_wk] );\r
+       BBAnd( bb_chk, bb_chk, bb_desti );\r
+       BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      }\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(bishop)\r
+           | Cap2Move(-BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+\r
+\r
+  bb_piece = BB_BTGOLD;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = LastOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      bb_chk = abb_w_gold_attacks[sq_wk];\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      BBAnd( bb_chk, bb_chk, abb_b_gold_attacks[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = ( To2Move(to) | From2Move(from)\r
+                      | Piece2Move(BOARD[from])\r
+                      | Cap2Move(-BOARD[to]) );\r
+       }\r
+    }\r
+  \r
+\r
+  u0 = BB_BSILVER.p[0];\r
+  while( u0 )\r
+    {\r
+      from = last_one0( u0 );\r
+      u0   ^= abb_mask[from].p[0];\r
+\r
+      bb_chk.p[0] = abb_w_gold_attacks[sq_wk].p[0];\r
+      bb_chk.p[1] = abb_w_gold_attacks[sq_wk].p[1];\r
+      bb_chk.p[2] = 0;\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      bb_chk.p[0] &= bb_move_to.p[0] & abb_b_silver_attacks[from].p[0];\r
+      bb_chk.p[1] &= bb_move_to.p[1] & abb_b_silver_attacks[from].p[1];\r
+\r
+      while( bb_chk.p[0] | bb_chk.p[1] )\r
+       {\r
+         to          = last_one01( bb_chk.p[0], bb_chk.p[1] );\r
+         bb_chk.p[0] ^= abb_mask[to].p[0];\r
+         bb_chk.p[1] ^= abb_mask[to].p[1];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(silver)\r
+           | Cap2Move(-BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+  \r
+\r
+  u1 = BB_BSILVER.p[1] & 0x7fc0000U;\r
+  while( u1 )\r
+    {\r
+      from = last_one1( u1 );\r
+      u1   ^= abb_mask[from].p[1];\r
+      \r
+      bb_chk.p[0] = abb_w_gold_attacks[sq_wk].p[0];\r
+      bb_chk.p[1] = bb_chk.p[2] = 0;\r
+      \r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      bb_chk.p[0] &= bb_move_to.p[0] & abb_b_silver_attacks[from].p[0];\r
+      while ( bb_chk.p[0] )\r
+       {\r
+         to          = last_one0( bb_chk.p[0] );\r
+         bb_chk.p[0] ^= abb_mask[to].p[0];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(silver)\r
+           | Cap2Move(-BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+  \r
+\r
+  bb_piece = BB_BSILVER;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = LastOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      bb_chk = abb_w_silver_attacks[sq_wk];\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      BBAnd( bb_chk, bb_chk, abb_b_silver_attacks[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(silver)\r
+           | Cap2Move(-BOARD[to]);\r
+       }\r
+    }\r
+  \r
+\r
+  u0 = BB_BKNIGHT.p[0];\r
+  u1 = BB_BKNIGHT.p[1] & 0x7fffe00U;\r
+  while( u0 | u1 )\r
+    {\r
+      from = last_one01( u0, u1 );\r
+      u0   ^= abb_mask[from].p[0];\r
+      u1   ^= abb_mask[from].p[1];\r
+\r
+      bb_chk.p[0] = abb_w_gold_attacks[sq_wk].p[0];\r
+      bb_chk.p[1] = bb_chk.p[2] = 0;\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      bb_chk.p[0] &= abb_b_knight_attacks[from].p[0] & bb_move_to.p[0];\r
+\r
+      while( bb_chk.p[0] )\r
+       {\r
+         to          = last_one0( bb_chk.p[0] );\r
+         bb_chk.p[0] ^= abb_mask[to].p[0];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(knight)\r
+                      | Cap2Move(-BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+  \r
+\r
+  u2 = BB_BKNIGHT.p[2];\r
+  u1 = BB_BKNIGHT.p[1] & 0x3ffffU;\r
+  while( u2 | u1 )\r
+    {\r
+      from = last_one12( u1, u2 );\r
+      u2   ^= abb_mask[from].p[2];\r
+      u1   ^= abb_mask[from].p[1];\r
+\r
+      bb_chk = abb_w_knight_attacks[sq_wk];\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      BBAnd( bb_chk, bb_chk, abb_b_knight_attacks[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(knight)\r
+           | Cap2Move(-BOARD[to]);\r
+       }\r
+    }\r
+\r
+\r
+  bb_piece = BB_BLANCE;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = LastOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      bb_chk.p[0] = abb_w_gold_attacks[sq_wk].p[0];\r
+      bb_chk.p[1] = bb_chk.p[2] = 0;\r
+\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+       }\r
+\r
+      BBAnd( bb_chk, bb_chk, AttackFile( from ) );\r
+      BBAnd( bb_chk, bb_chk, abb_minus_rays[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(lance)\r
+           | Cap2Move(-BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+  \r
+\r
+  u1 = BB_BLANCE.p[1];\r
+  u2 = BB_BLANCE.p[2];\r
+  while( u1| u2 )\r
+    {\r
+      from = last_one12( u1, u2 );\r
+      u1   ^= abb_mask[from].p[1];\r
+      u2   ^= abb_mask[from].p[2];\r
+\r
+      bb_chk = bb_file_chk;\r
+      idirec = (int)adirec[sq_wk][from];\r
+      if ( idirec && is_pinned_on_white_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_wk, bb_chk );\r
+         BBAnd( bb_chk, bb_chk, abb_minus_rays[from] );\r
+       }\r
+      else { BBAnd( bb_chk, bb_file_chk, abb_plus_rays[sq_wk] );}\r
+\r
+      BBAnd( bb_chk, bb_chk, AttackFile( from ) );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      bb_chk.p[0] = bb_chk.p[0] & 0x1ffU;\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(lance)\r
+           | Cap2Move(-BOARD[to]);\r
+       }\r
+    }\r
+\r
+\r
+  BBAnd( bb_piece, bb_diag1_chk, BB_BPAWN );\r
+  while ( BBToU(bb_piece) )\r
+    {\r
+      from = LastOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+      \r
+      to = from - nfile;\r
+      if ( BOARD[to] != empty ) { continue; }\r
+\r
+      bb_desti = AttackDiag1( from );\r
+      if ( BBContract( bb_desti, BB_B_BH ) )\r
+       {\r
+         *pmove = To2Move(to) | From2Move(from)\r
+           | Piece2Move(pawn) | Cap2Move(-BOARD[to]);\r
+         if ( from < A5 ) { *pmove |= FLAG_PROMO; }\r
+         pmove += 1;\r
+       }\r
+    }\r
+\r
+  BBAnd( bb_piece, bb_diag2_chk, BB_BPAWN );\r
+  while ( BBToU(bb_piece) )\r
+    {\r
+      from = LastOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+      \r
+      to = from - nfile;\r
+      if ( BOARD[to] != empty ) { continue; }\r
+\r
+      bb_desti = AttackDiag2( from );\r
+      if ( BBContract( bb_desti, BB_B_BH ) )\r
+       {\r
+         *pmove = To2Move(to) | From2Move(from)\r
+           | Piece2Move(pawn) | Cap2Move(-BOARD[to]);\r
+         if ( from < A5 ) { *pmove |= FLAG_PROMO; }\r
+         pmove += 1;\r
+       }\r
+    }\r
+\r
+  BBIni( bb_chk );\r
+  bb_chk.p[0] = abb_w_gold_attacks[sq_wk].p[0];\r
+  if ( sq_wk < A2 ) { BBOr( bb_chk, bb_chk, abb_mask[sq_wk+nfile] ); };\r
+  BBAnd( bb_chk, bb_chk, bb_move_to );\r
+  BBAnd( bb_chk, bb_chk, BB_BPAWN_ATK );\r
+  while ( BBToU(bb_chk) )\r
+    {\r
+      to = LastOne( bb_chk );\r
+      Xor( to, bb_chk );\r
+\r
+      from = to + nfile;\r
+      *pmove = To2Move(to) | From2Move(from)\r
+       | Piece2Move(pawn) | Cap2Move(-BOARD[to]);\r
+      if ( from < A5 ) { *pmove |= FLAG_PROMO; }\r
+      pmove += 1;\r
+    }\r
+\r
+\r
+  if ( IsHandGold(HAND_B) )\r
+    {\r
+      BBAnd( bb_chk, bb_drop_to, abb_w_gold_attacks[sq_wk] );\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | Drop2Move(gold);\r
+       }\r
+    }\r
+  \r
+\r
+  if ( IsHandSilver(HAND_B) )\r
+    {\r
+      BBAnd( bb_chk, bb_drop_to, abb_w_silver_attacks[sq_wk] );\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | Drop2Move(silver);\r
+       }\r
+    }\r
+  \r
+\r
+  if ( IsHandKnight(HAND_B) && sq_wk < A2 )\r
+    {\r
+      to = sq_wk + 2*nfile - 1;\r
+      if ( aifile[sq_wk] != file1 && BOARD[to] == empty )\r
+       {\r
+         *pmove++ = To2Move(to) | Drop2Move(knight);\r
+       }\r
+\r
+      to = sq_wk + 2*nfile + 1;\r
+      if ( aifile[sq_wk] != file9 && BOARD[to] == empty )\r
+       {\r
+         *pmove++ = To2Move(to) | Drop2Move(knight);\r
+       }\r
+    }\r
+\r
+\r
+  if ( IsHandPawn(HAND_B)\r
+       && sq_wk < A1\r
+       && ! ( BBToU(BB_BPAWN) & ( mask_file1 >> aifile[sq_wk] ) ) )\r
+    {\r
+      to = sq_wk + nfile;\r
+      if ( BOARD[to] == empty && ! is_mate_b_pawn_drop( __ptree__, to ) )\r
+       {\r
+         *pmove++ = To2Move(to) | Drop2Move(pawn);\r
+       }\r
+    }\r
+\r
+\r
+  if ( IsHandLance(HAND_B) )\r
+    {\r
+      unsigned int move;\r
+      int dist, min_dist;\r
+\r
+      if ( (int)aifile[sq_wk] == file1\r
+          || (int)aifile[sq_wk] == file9 ) { min_dist = 2; }\r
+      else                                  { min_dist = 3; }\r
+\r
+      for ( to = sq_wk+nfile, dist = 1; to < nsquare && BOARD[to] == empty;\r
+           to += nfile, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(lance);\r
+         if      ( dist == 1 )       { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+    }\r
+\r
+\r
+  if ( IsHandRook(HAND_B) )\r
+    {\r
+      unsigned int move;\r
+      int file, dist, min_dist;\r
+\r
+      if ( (int)aifile[sq_wk] == file1\r
+          || (int)aifile[sq_wk] == file9 ) { min_dist = 2; }\r
+      else                                  { min_dist = 3; }\r
+\r
+      for ( to = sq_wk+nfile, dist = 1; to < nsquare && BOARD[to] == empty;\r
+           to += nfile, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(rook);\r
+         if      ( dist == 1 )       { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      for ( file = (int)aifile[sq_wk]-1, to = sq_wk-1, dist = 1;\r
+           file >= file1 && BOARD[to] == empty;\r
+           file -= 1, to -= 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(rook);\r
+         if      ( dist == 1 ) { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      if ( sq_wk < A8 || I2 < sq_wk ) { min_dist = 2; }\r
+      else                            { min_dist = 3; }\r
+\r
+      for ( file = (int)aifile[sq_wk]+1, to = sq_wk+1, dist = 1;\r
+           file <= file9 && BOARD[to] == empty;\r
+           file += 1, to += 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(rook);\r
+         if      ( dist == 1 )       { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      for ( to = sq_wk-nfile, dist = 1; to >= 0 && BOARD[to] == empty;\r
+           to -= nfile, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(rook);\r
+         if ( (int)airank[to] == rank3 ) { move |= MOVE_CHK_CLEAR; }\r
+         if      ( dist == 1 )           { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist )     { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+    }\r
+\r
+\r
+  if ( IsHandBishop(HAND_B) )\r
+    {\r
+      unsigned int move;\r
+      int file, rank, dist;\r
+\r
+      to   = sq_wk;\r
+      file = (int)aifile[sq_wk];\r
+      rank = (int)airank[sq_wk];\r
+      for ( to -= 10, file -= 1, rank -= 1, dist = 1;\r
+           file >= 0 && rank >= 0 && BOARD[to] == empty;\r
+           to -= 10, file -= 1, rank -= 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(bishop);\r
+         if ( rank == rank3 ) { move |= MOVE_CHK_CLEAR; }\r
+         if ( dist == 1 )     { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > 2 ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      to   = sq_wk;\r
+      file = (int)aifile[sq_wk];\r
+      rank = (int)airank[sq_wk];\r
+      for ( to -= 8, file += 1, rank -= 1, dist = 1;\r
+           file <= file9 && rank >= 0 && BOARD[to] == empty;\r
+           to -= 8, file += 1, rank -= 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(bishop);\r
+         if ( rank == rank3 ) { move |= MOVE_CHK_CLEAR; }\r
+         if ( dist == 1 )     { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > 2 ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      to   = sq_wk;\r
+      file = (int)aifile[sq_wk];\r
+      rank = (int)airank[sq_wk];\r
+      for ( to += 8, file -= 1, rank += 1, dist = 1;\r
+           file >= 0 && rank <= rank9 && BOARD[to] == empty;\r
+           to += 8, file -= 1, rank += 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(bishop);\r
+         if ( dist == 1 )     { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > 2 ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      to   = sq_wk;\r
+      file = (int)aifile[sq_wk];\r
+      rank = (int)airank[sq_wk];\r
+      for ( to += 10, file += 1, rank += 1, dist = 1;\r
+           file <= file9 && rank <= rank9 && BOARD[to] == empty;\r
+           to += 10, file += 1, rank += 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(bishop);\r
+         if ( dist == 1 )     { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > 2 ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+    }\r
+\r
+\r
+  return pmove;\r
+}\r
+\r
+\r
+unsigned int *\r
+w_gen_checks( tree_t * restrict __ptree__, unsigned int * restrict pmove )\r
+{\r
+  bitboard_t bb_piece, bb_rook_chk, bb_bishop_chk, bb_chk, bb_move_to;\r
+  bitboard_t bb_diag1_chk, bb_diag2_chk, bb_file_chk, bb_drop_to, bb_desti;\r
+  const tree_t * restrict ptree = __ptree__;\r
+  unsigned int u0, u1, u2;\r
+  int from, to, sq_bk, idirec;\r
+\r
+  sq_bk = SQ_BKING;\r
+  bb_rook_chk = bb_file_chk = AttackFile( sq_bk );\r
+  bb_rook_chk.p[aslide[sq_bk].ir0] |= AttackRank( sq_bk );\r
+  bb_diag1_chk = AttackDiag1( sq_bk );\r
+  bb_diag2_chk = AttackDiag2( sq_bk );\r
+  AttackBishop( bb_bishop_chk, sq_bk );\r
+  BBNot( bb_move_to, BB_WOCCUPY );\r
+  BBOr( bb_drop_to, BB_BOCCUPY, BB_WOCCUPY );\r
+  BBNot( bb_drop_to, bb_drop_to );\r
+\r
+\r
+  from  = SQ_WKING;\r
+  idirec = (int)adirec[sq_bk][from];\r
+  if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+    {\r
+      BBIni( bb_chk );\r
+      bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+      BBAnd( bb_chk, bb_chk, abb_king_attacks[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(king)\r
+           | Cap2Move(BOARD[to]);\r
+       }\r
+    }\r
+\r
+\r
+  bb_piece = BB_WDRAGON;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = FirstOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      BBOr( bb_chk, bb_rook_chk, abb_king_attacks[sq_bk] );\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      AttackDragon( bb_desti, from );\r
+      BBAnd( bb_chk, bb_chk, bb_desti );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = LastOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(dragon)\r
+           | Cap2Move(BOARD[to]);\r
+       }\r
+    }\r
+\r
+\r
+  bb_piece = BB_WHORSE;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = FirstOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      BBOr( bb_chk, bb_bishop_chk, abb_king_attacks[sq_bk] );\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      AttackHorse( bb_desti, from );\r
+      BBAnd( bb_chk, bb_chk, bb_desti );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(horse)\r
+           | Cap2Move(BOARD[to]);\r
+       }\r
+    }\r
+\r
+  u0 = BB_WROOK.p[0];\r
+  u1 = BB_WROOK.p[1];\r
+  while( u0 | u1 )\r
+    {\r
+      from = first_one01( u0, u1 );\r
+      u0   ^= abb_mask[from].p[0];\r
+      u1   ^= abb_mask[from].p[1];\r
+\r
+      AttackRook( bb_desti, from );\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         BBAnd( bb_chk, bb_desti, bb_move_to );\r
+       }\r
+      else {\r
+       bb_chk       = bb_rook_chk;\r
+       bb_chk.p[2] |= abb_king_attacks[sq_bk].p[2];\r
+       BBAnd( bb_chk, bb_chk, bb_desti );\r
+       BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      }\r
+\r
+      while ( bb_chk.p[2] )\r
+       {\r
+         to          = first_one2( bb_chk.p[2] );\r
+         bb_chk.p[2] ^= abb_mask[to].p[2];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(rook)\r
+           | Cap2Move(BOARD[to]) | FLAG_PROMO;\r
+       }\r
+\r
+      while( bb_chk.p[0] | bb_chk.p[1] )\r
+       {\r
+         to          = first_one01( bb_chk.p[0], bb_chk.p[1] );\r
+         bb_chk.p[0] ^= abb_mask[to].p[0];\r
+         bb_chk.p[1] ^= abb_mask[to].p[1];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(rook)\r
+           | Cap2Move(BOARD[to]);\r
+       }\r
+    }\r
+\r
+  u2 = BB_WROOK.p[2];\r
+  while( u2 )\r
+    {\r
+      from = first_one2( u2 );\r
+      u2   ^= abb_mask[from].p[2];\r
+      \r
+      AttackRook( bb_desti, from );\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         BBAnd( bb_chk, bb_desti, bb_move_to );\r
+       }\r
+      else {\r
+       BBOr( bb_chk, bb_rook_chk, abb_king_attacks[sq_bk] );\r
+       BBAnd( bb_chk, bb_chk, bb_desti );\r
+       BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      }\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(rook)\r
+           | Cap2Move(BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+\r
+  u0 = BB_WBISHOP.p[0];\r
+  u1 = BB_WBISHOP.p[1];\r
+  while( u0 | u1 )\r
+    {\r
+      from = first_one01( u0, u1 );\r
+      u0   ^= abb_mask[from].p[0];\r
+      u1   ^= abb_mask[from].p[1];\r
+\r
+      AttackBishop( bb_desti, from );\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         BBAnd( bb_chk, bb_desti, bb_move_to );\r
+       }\r
+      else {\r
+       bb_chk       = bb_bishop_chk;\r
+       bb_chk.p[2] |= abb_king_attacks[sq_bk].p[2];\r
+       BBAnd( bb_chk, bb_chk, bb_desti );\r
+       BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      }\r
+\r
+      while ( bb_chk.p[2] )\r
+       {\r
+         to          = first_one2( bb_chk.p[2] );\r
+         bb_chk.p[2] ^= abb_mask[to].p[2];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(bishop)\r
+           | Cap2Move(BOARD[to]) | FLAG_PROMO;\r
+       }\r
+\r
+      while( bb_chk.p[0] | bb_chk.p[1] )\r
+       {\r
+         to          = first_one01( bb_chk.p[0], bb_chk.p[1] );\r
+         bb_chk.p[0] ^= abb_mask[to].p[0];\r
+         bb_chk.p[1] ^= abb_mask[to].p[1];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(bishop)\r
+           | Cap2Move(BOARD[to]);\r
+       }\r
+    }\r
+\r
+  u2 = BB_WBISHOP.p[2];\r
+  while( u2 )\r
+    {\r
+      from = first_one2( u2 );\r
+      u2   ^= abb_mask[from].p[2];\r
+      \r
+      AttackBishop( bb_desti, from );\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         BBAnd( bb_chk, bb_desti, bb_move_to );\r
+       }\r
+      else {\r
+       BBOr( bb_chk, bb_bishop_chk, abb_king_attacks[sq_bk] );\r
+       BBAnd( bb_chk, bb_chk, bb_desti );\r
+       BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      }\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(bishop)\r
+           | Cap2Move(BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+\r
+\r
+  bb_piece = BB_WTGOLD;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = FirstOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      bb_chk = abb_b_gold_attacks[sq_bk];\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      BBAnd( bb_chk, bb_chk, abb_w_gold_attacks[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = ( To2Move(to) | From2Move(from)\r
+                      | Piece2Move(-BOARD[from])\r
+                      | Cap2Move(BOARD[to]) );\r
+       }\r
+    }\r
+\r
+  \r
+  u2 = BB_WSILVER.p[2];\r
+  while( u2 )\r
+    {\r
+      from = first_one2( u2 );\r
+      u2   ^= abb_mask[from].p[2];\r
+\r
+      bb_chk.p[2] = abb_b_gold_attacks[sq_bk].p[2];\r
+      bb_chk.p[1] = abb_b_gold_attacks[sq_bk].p[1];\r
+      bb_chk.p[0] = 0;\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      bb_chk.p[2] &= bb_move_to.p[2] & abb_w_silver_attacks[from].p[2];\r
+      bb_chk.p[1] &= bb_move_to.p[1] & abb_w_silver_attacks[from].p[1];\r
+\r
+      while( bb_chk.p[2] | bb_chk.p[1] )\r
+       {\r
+         to          = first_one12( bb_chk.p[1], bb_chk.p[2] );\r
+         bb_chk.p[1] ^= abb_mask[to].p[1];\r
+         bb_chk.p[2] ^= abb_mask[to].p[2];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(silver)\r
+           | Cap2Move(BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+  \r
+\r
+  u1 = BB_WSILVER.p[1] & 0x1ffU;\r
+  while( u1 )\r
+    {\r
+      from = first_one1( u1 );\r
+      u1   ^= abb_mask[from].p[1];\r
+      \r
+      bb_chk.p[2] = abb_b_gold_attacks[sq_bk].p[2];\r
+      bb_chk.p[1] = bb_chk.p[0] = 0;\r
+      \r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      bb_chk.p[2] &= bb_move_to.p[2] & abb_w_silver_attacks[from].p[2];\r
+      while ( bb_chk.p[2] )\r
+       {\r
+         to          = first_one2( bb_chk.p[2] );\r
+         bb_chk.p[2] ^= abb_mask[to].p[2];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(silver)\r
+           | Cap2Move(BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+  \r
+\r
+  bb_piece = BB_WSILVER;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = FirstOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      bb_chk = abb_b_silver_attacks[sq_bk];\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      BBAnd( bb_chk, bb_chk, abb_w_silver_attacks[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(silver)\r
+           | Cap2Move(BOARD[to]);\r
+       }\r
+    }\r
+\r
+  \r
+  u2 = BB_WKNIGHT.p[2];\r
+  u1 = BB_WKNIGHT.p[1] & 0x3ffffU;\r
+  while( u2 | u1 )\r
+    {\r
+      from = first_one12( u1, u2 );\r
+      u2   ^= abb_mask[from].p[2];\r
+      u1   ^= abb_mask[from].p[1];\r
+\r
+      bb_chk.p[2] = abb_b_gold_attacks[sq_bk].p[2];\r
+      bb_chk.p[1] = bb_chk.p[0] = 0;\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      bb_chk.p[2] &= abb_w_knight_attacks[from].p[2] & bb_move_to.p[2];\r
+\r
+      while( bb_chk.p[2] )\r
+       {\r
+         to          = first_one2( bb_chk.p[2] );\r
+         bb_chk.p[2] ^= abb_mask[to].p[2];\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(knight)\r
+                      | Cap2Move(BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+  \r
+\r
+  u0 = BB_WKNIGHT.p[0];\r
+  u1 = BB_WKNIGHT.p[1] & 0x7fffe00U;\r
+  while( u0 | u1 )\r
+    {\r
+      from = first_one01( u0, u1 );\r
+      u0   ^= abb_mask[from].p[0];\r
+      u1   ^= abb_mask[from].p[1];\r
+\r
+      bb_chk = abb_b_knight_attacks[sq_bk];\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      BBAnd( bb_chk, bb_chk, abb_w_knight_attacks[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(knight)\r
+           | Cap2Move(BOARD[to]);\r
+       }\r
+    }\r
+\r
+\r
+  bb_piece = BB_WLANCE;\r
+  while( BBToU( bb_piece ) )\r
+    {\r
+      from = FirstOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+\r
+      bb_chk.p[2] = abb_b_gold_attacks[sq_bk].p[2];\r
+      bb_chk.p[1] = bb_chk.p[0] = 0;\r
+\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+       }\r
+\r
+      BBAnd( bb_chk, bb_chk, AttackFile( from ) );\r
+      BBAnd( bb_chk, bb_chk, abb_plus_rays[from] );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(lance)\r
+           | Cap2Move(BOARD[to]) | FLAG_PROMO;\r
+       }\r
+    }\r
+  \r
+\r
+  u0 = BB_WLANCE.p[0];\r
+  u1 = BB_WLANCE.p[1];\r
+  while( u0 | u1 )\r
+    {\r
+      from = first_one01( u0, u1 );\r
+      u0   ^= abb_mask[from].p[0];\r
+      u1   ^= abb_mask[from].p[1];\r
+\r
+      bb_chk = bb_file_chk;\r
+      idirec = (int)adirec[sq_bk][from];\r
+      if ( idirec && is_pinned_on_black_king( ptree, from, idirec ) )\r
+       {\r
+         bb_chk = add_behind_attacks( idirec, sq_bk, bb_chk );\r
+         BBAnd( bb_chk, bb_chk, abb_plus_rays[from] );\r
+       }\r
+      else { BBAnd( bb_chk, bb_file_chk, abb_minus_rays[sq_bk] ); }\r
+\r
+      BBAnd( bb_chk, bb_chk, AttackFile( from ) );\r
+      BBAnd( bb_chk, bb_chk, bb_move_to );\r
+      bb_chk.p[2] = bb_chk.p[2] & 0x7fc0000U;\r
+\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(lance)\r
+           | Cap2Move(BOARD[to]);\r
+       }\r
+    }\r
+\r
+\r
+  BBAnd( bb_piece, bb_diag1_chk, BB_WPAWN );\r
+  while ( BBToU(bb_piece) )\r
+    {\r
+      from = FirstOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+      \r
+      to = from + nfile;\r
+      if ( BOARD[to] != empty ) { continue; }\r
+\r
+      bb_desti = AttackDiag1( from );\r
+      if ( BBContract( bb_desti, BB_W_BH ) )\r
+       {\r
+         *pmove = To2Move(to) | From2Move(from)\r
+           | Piece2Move(pawn) | Cap2Move(BOARD[to]);\r
+         if ( from > I5 ) { *pmove |= FLAG_PROMO; }\r
+         pmove += 1;\r
+       }\r
+    }\r
+\r
+  BBAnd( bb_piece, bb_diag2_chk, BB_WPAWN );\r
+  while ( BBToU(bb_piece) )\r
+    {\r
+      from = FirstOne( bb_piece );\r
+      Xor( from, bb_piece );\r
+      \r
+      to = from + nfile;\r
+      if ( BOARD[to] != empty ) { continue; }\r
+\r
+      bb_desti = AttackDiag2( from );\r
+      if ( BBContract( bb_desti, BB_W_BH ) )\r
+       {\r
+         *pmove = To2Move(to) | From2Move(from)\r
+           | Piece2Move(pawn) | Cap2Move(BOARD[to]);\r
+         if ( from > I5 ) { *pmove |= FLAG_PROMO; }\r
+         pmove += 1;\r
+       }\r
+    }\r
+\r
+  BBIni( bb_chk );\r
+  bb_chk.p[2] = abb_b_gold_attacks[sq_bk].p[2];\r
+  if ( sq_bk > I8 ) { BBOr( bb_chk, bb_chk, abb_mask[sq_bk-nfile] ); };\r
+  BBAnd( bb_chk, bb_chk, bb_move_to );\r
+  BBAnd( bb_chk, bb_chk, BB_WPAWN_ATK );\r
+  while ( BBToU(bb_chk) )\r
+    {\r
+      to = FirstOne( bb_chk );\r
+      Xor( to, bb_chk );\r
+\r
+      from = to - nfile;\r
+      *pmove = To2Move(to) | From2Move(from) | Piece2Move(pawn)\r
+       | Cap2Move(BOARD[to]);\r
+      if ( from > I5 ) { *pmove |= FLAG_PROMO; }\r
+      pmove += 1;\r
+    }\r
+\r
+\r
+  if ( IsHandGold(HAND_W) )\r
+    {\r
+      BBAnd( bb_chk, bb_drop_to, abb_b_gold_attacks[sq_bk] );\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | Drop2Move(gold);\r
+       }\r
+    }\r
+  \r
+\r
+  if ( IsHandSilver(HAND_W) )\r
+    {\r
+      BBAnd( bb_chk, bb_drop_to, abb_b_silver_attacks[sq_bk] );\r
+      while( BBToU( bb_chk ) )\r
+       {\r
+         to = FirstOne( bb_chk );\r
+         Xor( to, bb_chk );\r
+         *pmove++ = To2Move(to) | Drop2Move(silver);\r
+       }\r
+    }\r
+  \r
+\r
+  if ( IsHandKnight(HAND_W) && sq_bk > I8 )\r
+    {\r
+      to = sq_bk - 2*nfile - 1;\r
+      if ( aifile[sq_bk] != file1 && BOARD[to] == empty )\r
+       {\r
+         *pmove++ = To2Move(to) | Drop2Move(knight);\r
+       }\r
+\r
+      to = sq_bk - 2*nfile + 1;\r
+      if ( aifile[sq_bk] != file9 && BOARD[to] == empty )\r
+       {\r
+         *pmove++ = To2Move(to) | Drop2Move(knight);\r
+       }\r
+    }\r
+\r
+\r
+  if ( IsHandPawn(HAND_W)\r
+       && sq_bk > I9\r
+       && ! ( BBToU(BB_WPAWN) & ( mask_file1 >> aifile[sq_bk] ) ) )\r
+    {\r
+      to = sq_bk - nfile;\r
+      if ( BOARD[to] == empty && ! is_mate_w_pawn_drop( __ptree__, to ) )\r
+       {\r
+         *pmove++ = To2Move(to) | Drop2Move(pawn);\r
+       }\r
+    }\r
+\r
+\r
+  if ( IsHandLance(HAND_W) )\r
+    {\r
+      unsigned int move;\r
+      int dist, min_dist;\r
+\r
+      if ( (int)aifile[sq_bk] == file1\r
+          || (int)aifile[sq_bk] == file9 ) { min_dist = 2; }\r
+      else                                  { min_dist = 3; }\r
+\r
+      for ( to = sq_bk-nfile, dist = 1; to >= 0 && BOARD[to] == empty;\r
+           to -= nfile, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(lance);\r
+         if      ( dist == 1 )       { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+    }\r
+\r
+\r
+  if ( IsHandRook(HAND_W) )\r
+    {\r
+      unsigned int move;\r
+      int file, dist, min_dist;\r
+\r
+      if ( (int)aifile[sq_bk] == file1\r
+          || (int)aifile[sq_bk] == file9 ) { min_dist = 2; }\r
+      else                                  { min_dist = 3; }\r
+\r
+      for ( to = sq_bk-nfile, dist = 1; to >= 0 && BOARD[to] == empty;\r
+           to -= nfile, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(rook);\r
+         if      ( dist == 1 )        { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist )  { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      for ( to = sq_bk+nfile, dist = 1; to < nsquare && BOARD[to] == empty;\r
+           to += nfile, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(rook);\r
+         if ( (int)airank[to] == rank7 ) { move |= MOVE_CHK_CLEAR; }\r
+         if      ( dist == 1 )           { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist )     { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+\r
+      if ( sq_bk < A8 || I2 < sq_bk ) { min_dist = 2; }\r
+      else                            { min_dist = 3; }\r
+\r
+      for ( file = (int)aifile[sq_bk]+1, to = sq_bk+1, dist = 1;\r
+           file <= file9 && BOARD[to] == empty;\r
+           file += 1, to += 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(rook);\r
+         if      ( dist == 1 )       { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      for ( file = (int)aifile[sq_bk]-1, to = sq_bk-1, dist = 1;\r
+           file >= file1 && BOARD[to] == empty;\r
+           file -= 1, to -= 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(rook);\r
+         if      ( dist == 1 )           { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > min_dist )     { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+    }\r
+\r
+\r
+  if ( IsHandBishop(HAND_W) )\r
+    {\r
+      unsigned int move;\r
+      int file, rank, dist;\r
+\r
+      to   = sq_bk;\r
+      file = (int)aifile[sq_bk];\r
+      rank = (int)airank[sq_bk];\r
+      for ( to += 10, file += 1, rank += 1, dist = 1;\r
+           file <= file9 && rank <= rank9 && BOARD[to] == empty;\r
+           to += 10, file += 1, rank += 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(bishop);\r
+         if ( rank == rank7 ) { move |= MOVE_CHK_CLEAR; }\r
+         if ( dist == 1 )     { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > 2 ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      to   = sq_bk;\r
+      file = (int)aifile[sq_bk];\r
+      rank = (int)airank[sq_bk];\r
+      for ( to += 8, file -= 1, rank += 1, dist = 1;\r
+           file >= 0 && rank <= rank9 && BOARD[to] == empty;\r
+           to += 8, file -= 1, rank += 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(bishop);\r
+         if ( rank == rank7 ) { move |= MOVE_CHK_CLEAR; }\r
+         if ( dist == 1 )     { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > 2 ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      to   = sq_bk;\r
+      file = (int)aifile[sq_bk];\r
+      rank = (int)airank[sq_bk];\r
+      for ( to -= 8, file += 1, rank -= 1, dist = 1;\r
+           file <= file9 && rank >= 0 && BOARD[to] == empty;\r
+           to -= 8, file += 1, rank -= 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(bishop);\r
+         if ( dist == 1 )     { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > 2 ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+\r
+      to   = sq_bk;\r
+      file = (int)aifile[sq_bk];\r
+      rank = (int)airank[sq_bk];\r
+      for ( to -= 10, file -= 1, rank -= 1, dist = 1;\r
+           file >= 0 && rank >= 0 && BOARD[to] == empty;\r
+           to -= 10, file -= 1, rank -= 1, dist += 1 )\r
+       {\r
+         move = To2Move(to) | Drop2Move(bishop);\r
+         if ( dist == 1 )     { move |= MOVE_CHK_CLEAR; }\r
+         else if ( dist > 2 ) { move |= MOVE_CHK_SET; }\r
+         *pmove++ = move;\r
+       }\r
+    }\r
+\r
+\r
+  return pmove;\r
+}\r
+\r
+\r
+static bitboard_t\r
+add_behind_attacks( int idirec, int ik, bitboard_t bb )\r
+{\r
+  bitboard_t bb_tmp;\r
+\r
+  if ( idirec == direc_diag1 )\r
+    {\r
+      bb_tmp = abb_bishop_attacks_rr45[ik][0];\r
+    }\r
+  else if ( idirec == direc_diag2 )\r
+    {\r
+      bb_tmp = abb_bishop_attacks_rl45[ik][0];\r
+    }\r
+  else if ( idirec == direc_file )\r
+    {\r
+      bb_tmp = abb_file_attacks[ik][0];\r
+    }\r
+  else {\r
+    assert( idirec == direc_rank );\r
+    BBIni( bb_tmp );\r
+    bb_tmp.p[aslide[ik].ir0] = ai_rook_attacks_r0[ik][0];\r
+  }\r
+  BBNot( bb_tmp, bb_tmp );\r
+  BBOr( bb, bb, bb_tmp );\r
+\r
+  return bb;\r
+}\r
diff --git a/gendrop.c b/gendrop.c
new file mode 100644 (file)
index 0000000..4066827
--- /dev/null
+++ b/gendrop.c
@@ -0,0 +1,194 @@
+#include "shogi.h"
+
+unsigned int *
+b_gen_drop( tree_t * restrict __ptree__, unsigned int * restrict pmove )
+{
+  const tree_t * restrict ptree = __ptree__;
+  bitboard_t bb_target;
+  unsigned int ihand, ibb_target0a, ibb_target0b, ibb_pawn_cmp, utemp;
+  unsigned int ais_pawn[nfile];
+  int nhand, ito, i, nolance, noknight;
+  int ahand[6];
+
+  if ( ! HAND_B ) { return pmove; }     /* return! */
+  ihand = HAND_B;
+  nhand = 0;
+  if ( IsHandKnight( ihand ) ) { ahand[ nhand++ ] = Drop2Move(knight); }
+  noknight = nhand;
+  if ( IsHandLance( ihand ) )  { ahand[ nhand++ ] = Drop2Move(lance); }
+  nolance  = nhand;
+  if ( IsHandSilver( ihand ) ) { ahand[ nhand++ ] = Drop2Move(silver); }
+  if ( IsHandGold( ihand ) )   { ahand[ nhand++ ] = Drop2Move(gold); }
+  if ( IsHandBishop( ihand ) ) { ahand[ nhand++ ] = Drop2Move(bishop); }
+  if ( IsHandRook( ihand ) )   { ahand[ nhand++ ] = Drop2Move(rook); }
+
+  BBOr( bb_target, BB_BOCCUPY, BB_WOCCUPY );
+  BBNot( bb_target, bb_target );
+  ibb_target0a = bb_target.p[0] & 0x7fc0000U;
+  ibb_target0b = bb_target.p[0] & 0x003fe00U;
+  bb_target.p[0] &= 0x00001ffU;
+  bb_target.p[1] &= 0x7ffffffU;
+  bb_target.p[2] &= 0x7ffffffU;
+
+  if ( IsHandPawn( ihand ) )
+    {
+      ibb_pawn_cmp= BB_BPAWN_ATK.p[0] | BB_BPAWN_ATK.p[1] | BB_BPAWN_ATK.p[2];
+      ais_pawn[0] = ibb_pawn_cmp & ( mask_file1 >> 0 );
+      ais_pawn[1] = ibb_pawn_cmp & ( mask_file1 >> 1 );
+      ais_pawn[2] = ibb_pawn_cmp & ( mask_file1 >> 2 );
+      ais_pawn[3] = ibb_pawn_cmp & ( mask_file1 >> 3 );
+      ais_pawn[4] = ibb_pawn_cmp & ( mask_file1 >> 4 );
+      ais_pawn[5] = ibb_pawn_cmp & ( mask_file1 >> 5 );
+      ais_pawn[6] = ibb_pawn_cmp & ( mask_file1 >> 6 );
+      ais_pawn[7] = ibb_pawn_cmp & ( mask_file1 >> 7 );
+      ais_pawn[8] = ibb_pawn_cmp & ( mask_file1 >> 8 );
+      while ( BBToU( bb_target ) )
+       {
+         ito   = LastOne( bb_target );
+         utemp = To2Move(ito);
+         if ( ! ais_pawn[aifile[ito]] && ! IsMateBPawnDrop(__ptree__,ito) )
+           {
+             *pmove++ = utemp|Drop2Move(pawn);
+           }
+         for ( i = 0; i < nhand; i++ ) { *pmove++ = utemp | ahand[i]; }
+         Xor( ito, bb_target );
+       }
+
+      while ( ibb_target0b )
+       {
+         ito   = last_one0( ibb_target0b );
+         utemp = To2Move(ito);
+         if ( ! ais_pawn[aifile[ito]] && ! IsMateBPawnDrop(__ptree__,ito) )
+           {
+             *pmove++ = utemp | Drop2Move(pawn);
+           }
+         for ( i = noknight; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+         ibb_target0b ^= abb_mask[ito].p[0];
+       }
+    }
+  else {
+    while ( BBToU( bb_target ) )
+      {
+       ito   = LastOne( bb_target );
+       utemp = To2Move(ito);
+       for ( i = 0; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+       Xor( ito, bb_target );
+      }
+
+    while ( ibb_target0b )
+      {
+       ito = last_one0( ibb_target0b );
+       utemp = To2Move(ito);
+       for ( i = noknight; i < nhand; i++ ) { *pmove++ = utemp|ahand[ i ]; }
+       ibb_target0b ^= abb_mask[ ito ].p[0];
+      }
+  }
+
+  while ( ibb_target0a )
+    {
+      ito = last_one0( ibb_target0a );
+      utemp = To2Move(ito);
+      for ( i = nolance; i < nhand; i++ ) { *pmove++ = utemp|ahand[ i ]; }
+      ibb_target0a ^= abb_mask[ ito ].p[0];
+    }
+
+  return pmove;
+}
+
+
+unsigned int *
+w_gen_drop( tree_t * restrict __ptree__, unsigned int * restrict pmove )
+{
+  const tree_t * restrict ptree = __ptree__;
+  bitboard_t bb_target;
+  unsigned int ihand, ibb_target2a, ibb_target2b, ibb_pawn_cmp, utemp;
+  unsigned int ais_pawn[nfile];
+  int nhand, ito, i, nolance, noknight;
+  int ahand[6];
+
+  if ( ! HAND_W ) { return pmove; }     /* return! */
+  ihand = HAND_W;
+  nhand = 0;
+  if ( IsHandKnight( ihand ) ) { ahand[ nhand++ ] = Drop2Move(knight); }
+  noknight = nhand;
+  if ( IsHandLance( ihand ) )  { ahand[ nhand++ ] = Drop2Move(lance); }
+  nolance  = nhand;
+  if ( IsHandSilver( ihand ) ) { ahand[ nhand++ ] = Drop2Move(silver); }
+  if ( IsHandGold( ihand ) )   { ahand[ nhand++ ] = Drop2Move(gold); }
+  if ( IsHandBishop( ihand ) ) { ahand[ nhand++ ] = Drop2Move(bishop); }
+  if ( IsHandRook( ihand ) )   { ahand[ nhand++ ] = Drop2Move(rook); }
+
+  BBOr( bb_target, BB_BOCCUPY, BB_WOCCUPY );
+  BBNot( bb_target, bb_target );
+  ibb_target2a = bb_target.p[2] & 0x00001ffU;
+  ibb_target2b = bb_target.p[2] & 0x003fe00U;
+  bb_target.p[0] &= 0x7ffffffU;
+  bb_target.p[1] &= 0x7ffffffU;
+  bb_target.p[2] &= 0x7fc0000U;
+
+  if ( IsHandPawn( ihand ) )
+    {
+      ibb_pawn_cmp= BB_WPAWN_ATK.p[0] | BB_WPAWN_ATK.p[1] | BB_WPAWN_ATK.p[2];
+      ais_pawn[0] = ibb_pawn_cmp & ( mask_file1 >> 0 );
+      ais_pawn[1] = ibb_pawn_cmp & ( mask_file1 >> 1 );
+      ais_pawn[2] = ibb_pawn_cmp & ( mask_file1 >> 2 );
+      ais_pawn[3] = ibb_pawn_cmp & ( mask_file1 >> 3 );
+      ais_pawn[4] = ibb_pawn_cmp & ( mask_file1 >> 4 );
+      ais_pawn[5] = ibb_pawn_cmp & ( mask_file1 >> 5 );
+      ais_pawn[6] = ibb_pawn_cmp & ( mask_file1 >> 6 );
+      ais_pawn[7] = ibb_pawn_cmp & ( mask_file1 >> 7 );
+      ais_pawn[8] = ibb_pawn_cmp & ( mask_file1 >> 8 );
+      while ( BBToU( bb_target ) )
+       {
+         ito   = FirstOne( bb_target );
+         utemp = To2Move(ito);
+         if ( ! ais_pawn[aifile[ito]] && ! IsMateWPawnDrop(__ptree__,ito) )
+           {
+             *pmove++ = utemp | Drop2Move(pawn);
+           }
+         for ( i = 0; i < nhand; i++ ) { *pmove++ = utemp | ahand[i]; }
+         Xor( ito, bb_target );
+       }
+
+      while ( ibb_target2b )
+       {
+         ito   = first_one2( ibb_target2b );
+         utemp = To2Move(ito);
+         if ( ! ais_pawn[aifile[ito]] && ! IsMateWPawnDrop(__ptree__,ito) )
+           {
+             *pmove++ = utemp | Drop2Move(pawn);
+           }
+         for ( i = noknight; i < nhand; i++ ) { *pmove++ = utemp | ahand[i]; }
+         ibb_target2b ^= abb_mask[ito].p[2];
+       }
+    }
+  else {
+    while ( BBToU( bb_target ) )
+      {
+       ito   = FirstOne( bb_target );
+       utemp = To2Move(ito);
+       for ( i = 0; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+       Xor( ito, bb_target );
+      }
+
+    while ( ibb_target2b )
+      {
+       ito   = first_one2( ibb_target2b );
+       utemp = To2Move(ito);
+       for ( i = noknight; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+       ibb_target2b ^= abb_mask[ito].p[2];
+      }
+  }
+
+  while ( ibb_target2a )
+    {
+      ito   = first_one2( ibb_target2a );
+      utemp = To2Move(ito);
+      for ( i = nolance; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+      ibb_target2a ^= abb_mask[ito].p[2];
+    }
+
+  return pmove;
+}
diff --git a/genevasn.c b/genevasn.c
new file mode 100644 (file)
index 0000000..f34775b
--- /dev/null
@@ -0,0 +1,651 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+
+unsigned int *
+b_gen_evasion( tree_t * restrict ptree, unsigned int * restrict pmove )
+{
+  bitboard_t bb_desti, bb_checker, bb_inter, bb_target, bb_piece;
+  unsigned int hand, ubb_target0a, ubb_target0b, ubb_pawn_cmp, utemp;
+  unsigned ais_pawn[nfile];
+  int nchecker, sq_bk, to, sq_check, idirec;
+  int nhand, i, nolance, noknight, from;
+  int ahand[6];
+  
+  /* move the king */
+  sq_bk = SQ_BKING;
+  
+  Xor( sq_bk, BB_BOCCUPY );
+  XorFile( sq_bk, OCCUPIED_FILE );
+  XorDiag2( sq_bk, OCCUPIED_DIAG2 );
+  XorDiag1( sq_bk, OCCUPIED_DIAG1 );
+
+  BBNot( bb_desti, BB_BOCCUPY );
+  BBAnd( bb_desti, bb_desti, abb_king_attacks[sq_bk] );
+  utemp = From2Move(sq_bk) | Piece2Move(king);
+  while ( BBToU( bb_desti ) )
+    {
+      to = LastOne( bb_desti );
+      if ( ! is_black_attacked( ptree, to ) )
+       {
+         *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp;
+       }
+      Xor( to, bb_desti );
+    }
+  
+  Xor( sq_bk, BB_BOCCUPY );
+  XorFile( sq_bk, OCCUPIED_FILE );
+  XorDiag2( sq_bk, OCCUPIED_DIAG2 );
+  XorDiag1( sq_bk, OCCUPIED_DIAG1 );
+  
+  bb_checker = attacks_to_piece( ptree, sq_bk );
+  BBAnd( bb_checker, bb_checker, BB_WOCCUPY );
+  nchecker = PopuCount( bb_checker );
+  if ( nchecker == 2 ) { return pmove; }
+  
+  sq_check = LastOne( bb_checker );
+  bb_inter = abb_obstacle[sq_bk][sq_check];
+
+  /* move other pieces */
+  BBOr( bb_target, bb_inter, bb_checker );
+  
+  BBAnd( bb_desti, bb_target, BB_BPAWN_ATK );
+  while ( BBToU( bb_desti ) )
+    {
+      to = LastOne( bb_desti );
+      Xor( to, bb_desti );
+
+      from = to + 9;
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       {
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(pawn)
+                   | Cap2Move(-BOARD[to]) );
+         if ( to < A6 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_BLANCE;
+  while ( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      bb_desti = AttackFile( from );
+      BBAnd( bb_desti, bb_desti, abb_minus_rays[from] );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       {
+         to = LastOne( bb_desti );
+
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(lance)
+                   | Cap2Move(-BOARD[to]) );
+         if ( to <  A6 ) { *pmove++ = utemp | FLAG_PROMO; }
+         if ( to >= A7 ) { *pmove++ = utemp; }
+       }
+    }
+
+  bb_piece = BB_BKNIGHT;
+  while ( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_target, abb_b_knight_attacks[from] );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       do {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(knight)
+                   | Cap2Move(-BOARD[to]) );
+         if ( to <  A6 ) { *pmove++ = utemp | FLAG_PROMO; }
+         if ( to >= A7 ) { *pmove++ = utemp; }
+         
+       } while ( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_BSILVER;
+  while ( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+      
+      BBAnd( bb_desti, bb_target, abb_b_silver_attacks[from] );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       do {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(silver)
+                   | Cap2Move(-BOARD[to]) );
+         if ( from < A6 || to < A6 ) { *pmove++ = utemp | FLAG_PROMO; }
+         *pmove++ = utemp;
+       } while ( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_BTGOLD;
+  while( BBToU( bb_piece ) )
+    {
+      from  = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_target, abb_b_gold_attacks[from] );
+      if ( ! BBToU(bb_desti) ) { continue; }
+
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       do {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = ( To2Move(to) | From2Move(from)
+                      | Piece2Move(BOARD[from])
+                      | Cap2Move(-BOARD[to]) );
+       } while( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_BBISHOP;
+  while ( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      AttackBishop( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       do {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(bishop)
+                   | Cap2Move(-BOARD[to]) );
+         if ( from < A6 || to < A6 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       } while ( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_BROOK;
+  while ( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      AttackRook( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       do {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(rook)
+                   | Cap2Move(-BOARD[to]) );
+         if ( from < A6 || to < A6 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       } while ( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_BHORSE;
+  while( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      AttackHorse( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU(bb_desti) ) { continue; }
+
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       do {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti);
+         *pmove++ = ( To2Move(to) | From2Move(from) | Piece2Move(horse)
+                      | Cap2Move(-BOARD[to]) );
+       } while ( BBToU( bb_desti ) );
+    }
+  
+  bb_piece = BB_BDRAGON;
+  while( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      AttackDragon( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU(bb_desti) ) { continue; }
+
+      idirec = (int)adirec[sq_bk][from];
+      if ( ! idirec || ! is_pinned_on_black_king( ptree, from, idirec ) )
+       do {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = ( To2Move(to) | From2Move(from) | Piece2Move(dragon)
+                      | Cap2Move(-BOARD[to]) );
+       } while ( BBToU( bb_desti ) );
+    }
+
+  if ( ! HAND_B )          { return pmove; }
+  if ( ! BBToU(bb_inter) ) { return pmove; }
+
+  /* drops */
+  bb_target = bb_inter;
+  ubb_target0a = bb_target.p[0] & 0x7fc0000U;
+  ubb_target0b = bb_target.p[0] & 0x003fe00U;
+  bb_target.p[0] &= 0x00001ffU;
+  bb_target.p[1] &= 0x7ffffffU;
+  bb_target.p[2] &= 0x7ffffffU;
+
+  hand = HAND_B;
+  nhand = 0;
+  if ( IsHandKnight( hand ) ) { ahand[ nhand++ ] = Drop2Move(knight); }
+  noknight = nhand;
+  if ( IsHandLance( hand ) )  { ahand[ nhand++ ] = Drop2Move(lance); }
+  nolance  = nhand;
+  if ( IsHandSilver( hand ) ) { ahand[ nhand++ ] = Drop2Move(silver); }
+  if ( IsHandGold( hand ) )   { ahand[ nhand++ ] = Drop2Move(gold); }
+  if ( IsHandBishop( hand ) ) { ahand[ nhand++ ] = Drop2Move(bishop); }
+  if ( IsHandRook( hand ) )   { ahand[ nhand++ ] = Drop2Move(rook); }
+
+  if ( IsHandPawn( hand ) )
+    {
+      ubb_pawn_cmp= BBToU( BB_BPAWN_ATK );
+      ais_pawn[0] = ubb_pawn_cmp & ( mask_file1 >> 0 );
+      ais_pawn[1] = ubb_pawn_cmp & ( mask_file1 >> 1 );
+      ais_pawn[2] = ubb_pawn_cmp & ( mask_file1 >> 2 );
+      ais_pawn[3] = ubb_pawn_cmp & ( mask_file1 >> 3 );
+      ais_pawn[4] = ubb_pawn_cmp & ( mask_file1 >> 4 );
+      ais_pawn[5] = ubb_pawn_cmp & ( mask_file1 >> 5 );
+      ais_pawn[6] = ubb_pawn_cmp & ( mask_file1 >> 6 );
+      ais_pawn[7] = ubb_pawn_cmp & ( mask_file1 >> 7 );
+      ais_pawn[8] = ubb_pawn_cmp & ( mask_file1 >> 8 );
+      while ( BBToU( bb_target ) )
+       {
+         to = LastOne( bb_target );
+         utemp = To2Move(to);
+         if ( ! ais_pawn[aifile[to]] && ! IsMateBPawnDrop( ptree, to ) )
+           {
+             *pmove++ = utemp | Drop2Move(pawn);
+           }
+         for ( i = 0; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+         Xor( to, bb_target );
+       }
+
+      while ( ubb_target0b )
+       {
+         to = last_one0( ubb_target0b );
+         utemp = To2Move(to);
+         if ( ! ais_pawn[aifile[to]] && ! IsMateBPawnDrop( ptree, to ) )
+           {
+             *pmove++ = utemp | Drop2Move(pawn);
+           }
+         for ( i = noknight; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+         ubb_target0b ^= abb_mask[ to ].p[0];
+       }
+    }
+  else {
+    while ( BBToU( bb_target ) )
+      {
+       to = LastOne( bb_target );
+       utemp = To2Move(to);
+       for ( i = 0; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+       Xor( to, bb_target );
+      }
+
+    while ( ubb_target0b )
+      {
+       to = last_one0( ubb_target0b );
+       utemp = To2Move(to);
+       for ( i = noknight; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+       ubb_target0b ^= abb_mask[ to ].p[0];
+      }
+  }
+
+  while ( ubb_target0a )
+    {
+      to = last_one0( ubb_target0a );
+      utemp = To2Move(to);
+      for ( i = nolance; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+      ubb_target0a ^= abb_mask[ to ].p[0];
+    }
+
+  return pmove;
+}
+
+
+unsigned int *
+w_gen_evasion( tree_t * restrict ptree, unsigned int * restrict pmove )
+{
+  bitboard_t bb_desti, bb_checker, bb_inter, bb_target, bb_piece;
+  unsigned int hand, ubb_target2a, ubb_target2b, ubb_pawn_cmp, utemp;
+  unsigned int ais_pawn[nfile];
+  int nchecker, sq_wk, to, sq_check, idirec;
+  int nhand, i, nolance, noknight, from;
+  int ahand[6];
+
+  /* move the king */
+  sq_wk = SQ_WKING;
+
+  Xor( sq_wk, BB_WOCCUPY );
+  XorFile( sq_wk, OCCUPIED_FILE );
+  XorDiag2( sq_wk, OCCUPIED_DIAG2 );
+  XorDiag1( sq_wk, OCCUPIED_DIAG1 );
+
+  BBNot( bb_desti, BB_WOCCUPY );
+  BBAnd( bb_desti, bb_desti, abb_king_attacks[sq_wk] );
+  utemp = From2Move(sq_wk) | Piece2Move(king);
+  while ( BBToU( bb_desti ) )
+    {
+      to = FirstOne( bb_desti );
+      if ( ! is_white_attacked( ptree, to ) )
+       {
+         *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp;
+       }
+      Xor( to, bb_desti );
+    }
+
+  Xor( sq_wk, BB_WOCCUPY );
+  XorFile( sq_wk, OCCUPIED_FILE );
+  XorDiag2( sq_wk, OCCUPIED_DIAG2 );
+  XorDiag1( sq_wk, OCCUPIED_DIAG1 );
+
+  bb_checker = attacks_to_piece( ptree, sq_wk );
+  BBAnd( bb_checker, bb_checker, BB_BOCCUPY );
+  nchecker = PopuCount( bb_checker );
+  if ( nchecker == 2 ) { return pmove; }
+
+  sq_check = FirstOne( bb_checker );
+  bb_inter = abb_obstacle[sq_wk][sq_check];
+
+  /* move other pieces */
+  BBOr( bb_target, bb_inter, bb_checker );
+
+  BBAnd( bb_desti, bb_target, BB_WPAWN_ATK );
+  while ( BBToU( bb_desti ) )
+    {
+      to = FirstOne( bb_desti );
+      Xor( to, bb_desti );
+
+      from = to - 9;
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       {
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(pawn)
+                   | Cap2Move(BOARD[to]) );
+         if ( to > I4 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_WLANCE;
+  while ( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      bb_desti = AttackFile( from );
+      BBAnd( bb_desti, bb_desti, abb_plus_rays[from] );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       {
+         to = FirstOne( bb_desti );
+
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(lance)
+                   | Cap2Move(BOARD[to]) );
+         if ( to >  I4 ) { *pmove++ = utemp | FLAG_PROMO; }
+         if ( to <= I3 ) { *pmove++ = utemp; }
+       }
+    }
+
+  bb_piece = BB_WKNIGHT;
+  while ( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_target, abb_w_knight_attacks[from] );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       do {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(knight)
+                   | Cap2Move(BOARD[to]) );
+         if ( to >  I4 ) { *pmove++ = utemp | FLAG_PROMO; }
+         if ( to <= I3 ) { *pmove++ = utemp; }
+       } while ( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_WSILVER;
+  while ( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+      
+      BBAnd( bb_desti, bb_target, abb_w_silver_attacks[from] );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       do {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(silver)
+                   | Cap2Move(BOARD[to]) );
+         if ( from > I4 || to > I4 ) { *pmove++ = utemp | FLAG_PROMO; }
+         *pmove++ = utemp;
+       } while ( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_WTGOLD;
+  while( BBToU( bb_piece ) )
+    {
+      from  = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_target, abb_w_gold_attacks[from] );
+      if ( ! BBToU(bb_desti) ) { continue; }
+
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       do {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = ( To2Move(to) | From2Move(from)
+                      | Piece2Move(-BOARD[from])
+                      | Cap2Move(BOARD[to]) );
+       } while( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_WBISHOP;
+  while ( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      AttackBishop( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       do {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(bishop)
+                   | Cap2Move(BOARD[to]) );
+         if ( from > I4 || to > I4 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       } while ( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_WROOK;
+  while ( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      AttackRook( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU( bb_desti ) ) { continue; }
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       do {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+
+         utemp = ( To2Move(to) | From2Move(from) | Piece2Move(rook)
+                   | Cap2Move(BOARD[to]) );
+         if ( from > I4 || to > I4 ) { utemp |= FLAG_PROMO; }
+         *pmove++ = utemp;
+       } while ( BBToU( bb_desti ) );
+    }
+
+  bb_piece = BB_WHORSE;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      AttackHorse( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU(bb_desti) ) { continue; }
+
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       do {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti);
+         *pmove++ = ( To2Move(to) | From2Move(from) | Piece2Move(horse)
+                      | Cap2Move(BOARD[to]) );
+       } while ( BBToU( bb_desti ) );
+    }
+  
+  bb_piece = BB_WDRAGON;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      AttackDragon( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_target );
+      if ( ! BBToU(bb_desti) ) { continue; }
+
+      idirec = (int)adirec[sq_wk][from];
+      if ( ! idirec || ! is_pinned_on_white_king( ptree, from, idirec ) )
+       do {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = ( To2Move(to) | From2Move(from) | Piece2Move(dragon)
+                      | Cap2Move(BOARD[to]) );
+       } while ( BBToU( bb_desti ) );
+    }
+
+  if ( ! HAND_W )          { return pmove; }
+  if ( ! BBToU(bb_inter) ) { return pmove; }
+
+  /* drop */
+  bb_target = bb_inter;
+  ubb_target2a = bb_target.p[2] & 0x00001ffU;
+  ubb_target2b = bb_target.p[2] & 0x003fe00U;
+  bb_target.p[0] &= 0x7ffffffU;
+  bb_target.p[1] &= 0x7ffffffU;
+  bb_target.p[2] &= 0x7fc0000U;
+
+  hand = HAND_W;
+  nhand = 0;
+  if ( IsHandKnight( hand ) ) { ahand[ nhand++ ] = Drop2Move(knight); }
+  noknight = nhand;
+  if ( IsHandLance( hand ) )  { ahand[ nhand++ ] = Drop2Move(lance); }
+  nolance  = nhand;
+  if ( IsHandSilver( hand ) ) { ahand[ nhand++ ] = Drop2Move(silver); }
+  if ( IsHandGold( hand ) )   { ahand[ nhand++ ] = Drop2Move(gold); }
+  if ( IsHandBishop( hand ) ) { ahand[ nhand++ ] = Drop2Move(bishop); }
+  if ( IsHandRook( hand ) )   { ahand[ nhand++ ] = Drop2Move(rook); }
+
+  if ( IsHandPawn( hand ) )
+    {
+      ubb_pawn_cmp= BBToU( BB_WPAWN_ATK );
+      ais_pawn[0] = ubb_pawn_cmp & ( mask_file1 >> 0 );
+      ais_pawn[1] = ubb_pawn_cmp & ( mask_file1 >> 1 );
+      ais_pawn[2] = ubb_pawn_cmp & ( mask_file1 >> 2 );
+      ais_pawn[3] = ubb_pawn_cmp & ( mask_file1 >> 3 );
+      ais_pawn[4] = ubb_pawn_cmp & ( mask_file1 >> 4 );
+      ais_pawn[5] = ubb_pawn_cmp & ( mask_file1 >> 5 );
+      ais_pawn[6] = ubb_pawn_cmp & ( mask_file1 >> 6 );
+      ais_pawn[7] = ubb_pawn_cmp & ( mask_file1 >> 7 );
+      ais_pawn[8] = ubb_pawn_cmp & ( mask_file1 >> 8 );
+      while ( BBToU( bb_target ) )
+       {
+         to = FirstOne( bb_target );
+         utemp = To2Move(to);
+         if ( ! ais_pawn[aifile[to]] && ! IsMateWPawnDrop( ptree, to ) )
+           {
+             *pmove++ = utemp | Drop2Move(pawn);
+           }
+         for ( i = 0; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+         Xor( to, bb_target );
+       }
+
+      while ( ubb_target2b )
+       {
+         to = first_one2( ubb_target2b );
+         utemp = To2Move(to);
+         if ( ! ais_pawn[aifile[to]] && ! IsMateWPawnDrop( ptree, to ) )
+           {
+             *pmove++ = utemp | Drop2Move(pawn);
+           }
+         for ( i = noknight; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+         ubb_target2b ^= abb_mask[ to ].p[2];
+       }
+    }
+  else {
+    while ( BBToU( bb_target ) )
+      {
+       to = FirstOne( bb_target );
+       utemp = To2Move(to);
+       for ( i = 0; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+       Xor( to, bb_target );
+      }
+
+    while ( ubb_target2b )
+      {
+       to = first_one2( ubb_target2b );
+       utemp = To2Move(to);
+       for ( i = noknight; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+       ubb_target2b ^= abb_mask[ to ].p[2];
+      }
+  }
+
+  while ( ubb_target2a )
+    {
+      to = first_one2( ubb_target2a );
+      utemp = To2Move(to);
+      for ( i = nolance; i < nhand; i++ ) { *pmove++ = utemp|ahand[i]; }
+      ubb_target2a ^= abb_mask[ to ].p[2];
+    }
+
+  return pmove;
+}
diff --git a/gennocap.c b/gennocap.c
new file mode 100644 (file)
index 0000000..1f68b4b
--- /dev/null
@@ -0,0 +1,370 @@
+#include "shogi.h"
+
+unsigned int *
+b_gen_nocaptures( const tree_t * restrict ptree,
+                 unsigned int * restrict pmove )
+{
+  bitboard_t bb_empty, bb_piece, bb_desti;
+  unsigned int utemp;
+  int to, from;
+
+  BBOr( bb_empty, BB_BOCCUPY, BB_WOCCUPY );
+  BBNot( bb_empty, bb_empty );
+
+  bb_piece.p[1] = BB_BPAWN_ATK.p[1] & bb_empty.p[1];
+  bb_piece.p[2] = BB_BPAWN_ATK.p[2] & bb_empty.p[2];
+  while( bb_piece.p[1] | bb_piece.p[2] )
+    {
+      to            = last_one12( bb_piece.p[1], bb_piece.p[2] );
+      bb_piece.p[1] ^= abb_mask[to].p[1];
+      bb_piece.p[2] ^= abb_mask[to].p[2];
+      from          = to + 9;
+      *pmove++ = To2Move( to ) | From2Move( from ) | Piece2Move( pawn );
+    }
+
+  bb_piece = BB_BSILVER;
+  while( BBToU( bb_piece ) )
+    {
+      from   = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_empty, abb_b_silver_attacks[from] );
+      while ( BBToU( bb_desti ) )
+       {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+
+         utemp = To2Move( to ) | From2Move( from ) | Piece2Move( silver );
+         if ( from < A6 || to < A6 ) { *pmove++ = utemp | FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_BTGOLD;
+  while( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_empty, abb_b_gold_attacks[from] );
+      utemp = From2Move( from ) | Piece2Move( BOARD[from] ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  from = SQ_BKING;
+  BBAnd( bb_desti, bb_empty, abb_king_attacks[from] );
+  utemp = From2Move( from ) | Piece2Move( king ); 
+  while ( BBToU( bb_desti ) )
+    {
+      to = LastOne( bb_desti );
+      Xor( to, bb_desti );
+      *pmove++ = To2Move( to ) | utemp;
+    }
+
+  bb_piece.p[1] = BB_BBISHOP.p[1];
+  bb_piece.p[2] = BB_BBISHOP.p[2];
+  while( bb_piece.p[1] | bb_piece.p[2] )
+    {
+      from          = last_one12( bb_piece.p[1], bb_piece.p[2] );
+      bb_piece.p[1] ^= abb_mask[from].p[1];
+      bb_piece.p[2] ^= abb_mask[from].p[2];
+
+      AttackBishop( bb_desti, from );
+      bb_desti.p[1] &= bb_empty.p[1];
+      bb_desti.p[2] &= bb_empty.p[2];
+
+      utemp = From2Move( from ) | Piece2Move( bishop );
+      while ( bb_desti.p[1] | bb_desti.p[2] )
+       {
+         to            = last_one12( bb_desti.p[1], bb_desti.p[2] );
+         bb_desti.p[1] ^= abb_mask[to].p[1];
+         bb_desti.p[2] ^= abb_mask[to].p[2];
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_piece.p[1] = BB_BROOK.p[1];
+  bb_piece.p[2] = BB_BROOK.p[2];
+  while( bb_piece.p[1] | bb_piece.p[2] )
+    {
+      from          = last_one12( bb_piece.p[1], bb_piece.p[2] );
+      bb_piece.p[1] ^= abb_mask[from].p[1];
+      bb_piece.p[2] ^= abb_mask[from].p[2];
+
+      AttackRook( bb_desti, from );
+      bb_desti.p[1] &= bb_empty.p[1];
+      bb_desti.p[2] &= bb_empty.p[2];
+
+      utemp = From2Move( from ) | Piece2Move( rook );
+      while ( bb_desti.p[1] | bb_desti.p[2] )
+       {
+         to            = last_one12( bb_desti.p[1], bb_desti.p[2] );
+         bb_desti.p[1] ^= abb_mask[to].p[1];
+         bb_desti.p[2] ^= abb_mask[to].p[2];
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_piece = BB_BHORSE;
+  while( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+      
+      AttackHorse( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_empty );
+      utemp = From2Move( from ) | Piece2Move( horse ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_piece = BB_BDRAGON;
+  while( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+      
+      AttackDragon( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_empty );
+      utemp = From2Move( from ) | Piece2Move( dragon ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_empty.p[0] &= 0x1ffU;
+
+  bb_piece = BB_BLANCE;
+  while( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      bb_desti = AttackFile( from );
+      BBAnd( bb_desti, bb_desti, abb_minus_rays[from] );
+      BBAnd( bb_desti, bb_desti, bb_empty );
+
+      utemp = From2Move( from ) | Piece2Move( lance ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_piece = BB_BKNIGHT;
+  while( BBToU( bb_piece ) )
+    {
+      from = LastOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_empty, abb_b_knight_attacks[from] );
+      utemp = From2Move( from ) | Piece2Move( knight ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = LastOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  return pmove;
+}
+
+
+unsigned int *
+w_gen_nocaptures( const tree_t * restrict ptree,
+                 unsigned int * restrict pmove )
+{
+  bitboard_t bb_empty, bb_piece, bb_desti;
+  unsigned int utemp;
+  int to, from;
+
+  BBOr( bb_empty, BB_BOCCUPY, BB_WOCCUPY );
+  BBNot( bb_empty, bb_empty );
+
+  bb_piece.p[0] = BB_WPAWN_ATK.p[0] & bb_empty.p[0];
+  bb_piece.p[1] = BB_WPAWN_ATK.p[1] & bb_empty.p[1];
+  while( bb_piece.p[0] | bb_piece.p[1] )
+    {
+      to            = first_one01( bb_piece.p[0], bb_piece.p[1] );
+      bb_piece.p[0] ^= abb_mask[to].p[0];
+      bb_piece.p[1] ^= abb_mask[to].p[1];
+      from          = to - 9;
+      *pmove++ = To2Move( to ) | From2Move( from ) | Piece2Move( pawn );
+    }
+
+  bb_piece = BB_WSILVER;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_empty, abb_w_silver_attacks[from] );
+      while ( BBToU( bb_desti ) )
+       {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+
+         utemp = To2Move( to ) | From2Move( from ) | Piece2Move( silver );
+         if ( from > I4 || to > I4 ) { *pmove++ = utemp | FLAG_PROMO; }
+         *pmove++ = utemp;
+       }
+    }
+
+  bb_piece = BB_WTGOLD;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_empty, abb_w_gold_attacks[from] );
+      utemp = From2Move( from ) | Piece2Move( -BOARD[from] ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  from = SQ_WKING;
+  BBAnd( bb_desti, bb_empty, abb_king_attacks[from] );
+  utemp = From2Move( from ) | Piece2Move( king ); 
+  while ( BBToU( bb_desti ) )
+    {
+      to = FirstOne( bb_desti );
+      Xor( to, bb_desti );
+      *pmove++ = To2Move( to ) | utemp;
+    }
+
+  bb_piece.p[0] = BB_WBISHOP.p[0];
+  bb_piece.p[1] = BB_WBISHOP.p[1];
+  while( bb_piece.p[0] | bb_piece.p[1] )
+    {
+      from          = first_one01( bb_piece.p[0], bb_piece.p[1] );
+      bb_piece.p[0] ^= abb_mask[from].p[0];
+      bb_piece.p[1] ^= abb_mask[from].p[1];
+
+      AttackBishop( bb_desti, from );
+      bb_desti.p[0] &= bb_empty.p[0];
+      bb_desti.p[1] &= bb_empty.p[1];
+
+      utemp = From2Move( from ) | Piece2Move( bishop );
+      while ( bb_desti.p[0] | bb_desti.p[1] )
+       {
+         to            = first_one01( bb_desti.p[0], bb_desti.p[1] );
+         bb_desti.p[0] ^= abb_mask[to].p[0];
+         bb_desti.p[1] ^= abb_mask[to].p[1];
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_piece.p[0] = BB_WROOK.p[0];
+  bb_piece.p[1] = BB_WROOK.p[1];
+  while( bb_piece.p[0] | bb_piece.p[1] )
+    {
+      from          = first_one01( bb_piece.p[0], bb_piece.p[1] );
+      bb_piece.p[0] ^= abb_mask[from].p[0];
+      bb_piece.p[1] ^= abb_mask[from].p[1];
+
+      AttackRook( bb_desti, from );
+      bb_desti.p[0] &= bb_empty.p[0];
+      bb_desti.p[1] &= bb_empty.p[1];
+
+      utemp = From2Move( from ) | Piece2Move( rook );
+      while ( bb_desti.p[0] | bb_desti.p[1] )
+       {
+         to            = first_one01( bb_desti.p[0], bb_desti.p[1] );
+         bb_desti.p[0] ^= abb_mask[to].p[0];
+         bb_desti.p[1] ^= abb_mask[to].p[1];
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_piece = BB_WHORSE;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+      
+      AttackHorse( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_empty );
+      utemp = From2Move( from ) | Piece2Move( horse ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_piece = BB_WDRAGON;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+      
+      AttackDragon( bb_desti, from );
+      BBAnd( bb_desti, bb_desti, bb_empty );
+      utemp = From2Move( from ) | Piece2Move( dragon ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_empty.p[2] &= 0x7fc0000U;
+
+  bb_piece = BB_WLANCE;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      bb_desti = AttackFile( from );
+      BBAnd( bb_desti, bb_desti, abb_plus_rays[from] );
+      BBAnd( bb_desti, bb_desti, bb_empty );
+
+      utemp = From2Move( from ) | Piece2Move( lance ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  bb_piece = BB_WKNIGHT;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      Xor( from, bb_piece );
+
+      BBAnd( bb_desti, bb_empty, abb_w_knight_attacks[from] );
+      utemp = From2Move( from ) | Piece2Move( knight ); 
+      while ( BBToU( bb_desti ) )
+       {
+         to = FirstOne( bb_desti );
+         Xor( to, bb_desti );
+         *pmove++ = To2Move( to ) | utemp;
+       }
+    }
+
+  return pmove;
+}
diff --git a/hash.c b/hash.c
new file mode 100644 (file)
index 0000000..5ab568a
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,1107 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+#include "shogi.h"
+
+static int eval_supe( unsigned int hand_current, unsigned int hand_hash,
+                     int turn_current, int turn_hash,
+                     int * restrict pvalue_hash, int * restrict ptype_hash );
+
+int
+ini_trans_table( void )
+{
+  size_t size;
+  unsigned int ntrans_table;
+
+  ntrans_table = 1U << log2_ntrans_table;
+  size         = sizeof( trans_table_t ) * ntrans_table + 15U;
+  ptrans_table_orig = memory_alloc( size );
+  if ( ptrans_table_orig == NULL ) { return -1; }
+  ptrans_table = (trans_table_t *)( ((ptrdiff_t)ptrans_table_orig+15)
+                                   & ~(ptrdiff_t)15U );
+  hash_mask    = ntrans_table - 1;
+  Out( "Trans. Table Entries = %dK (%dMB)\n",
+       ( ntrans_table * 3U ) / 1024U, size / (1024U * 1024U ) );
+
+  return clear_trans_table();
+}
+
+
+#define Foo( PIECE, piece )  bb = BB_B ## PIECE;                    \
+                             while( BBToU(bb) ) {                   \
+                               sq = FirstOne( bb );                 \
+                               Xor( sq, bb );                       \
+                               key ^= ( b_ ## piece ## _rand )[sq]; \
+                             }                                      \
+                             bb = BB_W ## PIECE;                    \
+                             while( BBToU(bb) ) {                   \
+                               sq = FirstOne( bb );                 \
+                               Xor( sq, bb );                       \
+                               key ^= ( w_ ## piece ## _rand )[sq]; \
+                             }
+
+uint64_t
+hash_func( const tree_t * restrict ptree )
+{
+  uint64_t key = 0;
+  bitboard_t bb;
+  int sq;
+
+  key ^= b_king_rand[SQ_BKING];
+  key ^= w_king_rand[SQ_WKING];
+
+  Foo( PAWN,       pawn );
+  Foo( LANCE,      lance );
+  Foo( KNIGHT,     knight );
+  Foo( SILVER,     silver );
+  Foo( GOLD,       gold );
+  Foo( BISHOP,     bishop );
+  Foo( ROOK,       rook );
+  Foo( PRO_PAWN,   pro_pawn );
+  Foo( PRO_LANCE,  pro_lance );
+  Foo( PRO_KNIGHT, pro_knight );
+  Foo( PRO_SILVER, pro_silver );
+  Foo( HORSE,      horse );
+  Foo( DRAGON,     dragon );
+
+  return key;
+}
+
+#undef Foo
+
+
+/*
+       name    bits  shifts
+word1  depth     8     56
+       value    16     40
+       move     19     21
+       hand     21      0
+word2  key      57      7
+       turn      1      6
+       threat    1      5
+       type      2      3
+       age       3      0
+ */
+
+void
+hash_store( const tree_t * restrict ptree, int ply, int depth, int turn,
+           int value_type, int value, unsigned int move,
+           unsigned int state_node )
+{
+  uint64_t word1, word2, hash_word1, hash_word2;
+  unsigned int index, slot;
+  int depth_hash, age_hash;
+
+#if ! defined(MINIMUM)
+  if ( game_status & flag_learning ) { return; }
+#endif
+  assert( depth <= 0xff );
+
+  if ( depth < 0 ) { depth = 0; }
+  if ( abs(value) > score_max_eval )
+    {
+      if ( abs(value) > score_mate1ply ) { return; }
+      if ( value > 0 ) { value += ply-1; }
+      else             { value -= ply-1; }
+#if ! defined(MINIMUM)
+      if ( abs(value) > score_mate1ply )
+       {
+         out_warning( "A stored hash value is out of bounce!" );
+       }
+#endif
+    }
+  word2 = ( ( HASH_KEY & ~(uint64_t)0x7fU )
+           | (uint64_t)( (turn<<6) | ( state_node & node_mate_threat )
+                         | (value_type<<3) | trans_table_age ) );
+  word1 = ( ( (uint64_t)( depth<<16 | (value+32768) ) << 40 )
+           | ( (uint64_t)( move & 0x7ffffU ) << 21 )
+           | HAND_B );
+
+  index = (unsigned int)HASH_KEY & hash_mask;
+  hash_word1 = ptrans_table[index].prefer.word1;
+  hash_word2 = ptrans_table[index].prefer.word2;
+  SignKey( hash_word2, hash_word1 );
+  age_hash   = (int)((unsigned int)(hash_word2    ) & 0x07U);
+  depth_hash = (int)((unsigned int)(hash_word1>>56) & 0xffU);
+
+  SignKey( word2, word1 );
+
+  if ( age_hash != trans_table_age || depth_hash <= depth )
+    {
+      ptrans_table[index].prefer.word1 = word1;
+      ptrans_table[index].prefer.word2 = word2;
+    }
+  else {
+    slot = (unsigned int)HASH_KEY >> 31;
+    ptrans_table[index].always[slot].word1 = word1;
+    ptrans_table[index].always[slot].word2 = word2;
+  }
+}
+
+
+void
+hash_store_pv( const tree_t * restrict ptree, unsigned int move, int turn )
+{
+  uint64_t key_turn_pv, word1, word2;
+  unsigned int index;
+
+  key_turn_pv = ( HASH_KEY & ~(uint64_t)0x7fU ) | (unsigned int)( turn << 6 );
+  index       = (unsigned int)HASH_KEY & hash_mask;
+
+  word1 = ptrans_table[index].prefer.word1;
+  word2 = ptrans_table[index].prefer.word2;
+  SignKey( word2, word1 );
+
+  if ( ( (unsigned int)word1 & 0x1fffffU ) == HAND_B
+       && ( word2 & ~(uint64_t)0x3fU ) == key_turn_pv )
+    {
+      if ( ( (unsigned int)(word1>>21) & 0x7ffffU ) != ( move & 0x7ffffU ) )
+       {
+         word1 &= ~((uint64_t)0x7ffffU << 21);
+         word1 |= (uint64_t)( move & 0x7ffffU ) << 21;
+         word2 &= ~((uint64_t)0x3U << 3);
+         SignKey( word2, word1 );
+         ptrans_table[index].prefer.word1 = word1;
+         ptrans_table[index].prefer.word2 = word2;
+       }
+    }
+  else {
+    unsigned int slot;
+
+    slot = (unsigned int)HASH_KEY >> 31;
+    word1 = ptrans_table[index].always[slot].word1;
+    word2 = ptrans_table[index].always[slot].word2;
+    SignKey( word2, word1 );
+    if ( ( (unsigned int)word1 & 0x1fffffU ) == HAND_B
+        && ( word2 & ~(uint64_t)0x3fU ) == key_turn_pv )
+      {
+       if ( ( (unsigned int)(word1>>21) & 0x7ffffU )
+            != ( move & 0x7ffffU ) )
+         {
+           word1 &= ~((uint64_t)0x7ffffU << 21);
+           word1 |= (uint64_t)( move & 0x7ffffU ) << 21;
+           word2 &= ~((uint64_t)0x3U << 3);
+           SignKey( word2, word1 );
+           ptrans_table[index].always[slot].word1 = word1;
+           ptrans_table[index].always[slot].word2 = word2;
+         }
+      }
+    else {
+      word1  = (uint64_t)32768U << 40;
+      word1 |= (uint64_t)( move & 0x7ffffU ) << 21;
+      word1 |= HAND_B;
+      word2  = key_turn_pv | trans_table_age;
+      SignKey( word2, word1 );
+      ptrans_table[index].prefer.word1 = word1;
+      ptrans_table[index].prefer.word2 = word2;
+    }
+  }
+}
+
+
+trans_entry_t
+hash_learn_store( const tree_t * restrict ptree, int depth, int value,
+                 unsigned int move )
+{
+  trans_entry_t ret;
+
+  assert( 0 <= depth && depth <= 0xff );
+
+  ret.word2 = ( (HASH_KEY&(~(uint64_t)0x7fU))
+               | (uint64_t)( (root_turn<<6)
+                             | (value_exact<<3) | trans_table_age ) );
+  ret.word1 = ( ( (uint64_t)( depth<<16 | (value+32768) ) << 40 )
+               | ( (uint64_t)( move & 0x7ffffU ) << 21 )
+               | HAND_B );
+
+  return ret;
+}
+
+
+int
+all_hash_learn_store( void )
+{
+  uint64_t aword[2];
+  unsigned int u32key, unext, u, index;
+
+  if ( pf_hash == NULL ) { return 0; }
+
+  if ( fseek( pf_hash, sizeof(unsigned int), SEEK_SET ) == EOF
+       || fread( &unext, sizeof(unsigned int), 1, pf_hash ) != 1 )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  if ( ++unext == 0x10000U ) { unext = 0x1U; }
+  if ( fseek( pf_hash, (long)( 20U * unext ), SEEK_SET ) == EOF )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  for ( u = 0;; u++ )
+    {
+      if ( fread( &u32key, sizeof(unsigned int), 1, pf_hash ) != 1
+          || fread( aword, sizeof(uint64_t), 2, pf_hash ) != 2 )
+       {
+         str_error = str_io_error;
+         return -2;
+       }
+      index = u32key & hash_mask;
+      aword[1] |= (uint64_t)trans_table_age;
+      SignKey( aword[1], aword[0] );
+      ptrans_table[index].prefer.word1 = aword[0];
+      ptrans_table[index].prefer.word2 = aword[1];
+      if ( u == 0xfffeU ) { break; }
+      if ( ++unext == 0x10000U )
+       {
+         unext = 0x1U;
+         if ( fseek( pf_hash, 20, SEEK_SET ) == EOF )
+           {
+             str_error = str_io_error;
+             return -2;
+           }
+       }
+    }
+
+  return 1;
+}
+
+
+unsigned int
+hash_probe( tree_t * restrict ptree, int ply, int depth_current,
+           int turn_current, int alpha, int beta, unsigned int state_node )
+{
+  uint64_t word1, word2, key_current, key_hash;
+  unsigned int hand_hash, move_hash, move_infe, move_supe, slot, utemp;
+  unsigned int state_node_hash, index;
+  int null_depth, value_hash, ifrom;
+  int turn_hash, depth_hash, type_hash, is_superior;
+
+  ptree->ntrans_probe++;
+  move_supe   = 0;
+  move_infe   = 0;
+
+  if ( depth_current < 0 ) { depth_current = 0; }
+  null_depth  = NullDepth( depth_current );
+  if ( null_depth < PLY_INC ) { null_depth = 0; }
+
+  key_current = HASH_KEY & ~(uint64_t)0x7fU;
+
+  index = (unsigned int)HASH_KEY & hash_mask;
+  word1 = ptrans_table[index].prefer.word1;
+  word2 = ptrans_table[index].prefer.word2;
+  SignKey( word2, word1 );
+  key_hash = word2 & ~(uint64_t)0x7fU;
+
+  if ( key_hash == key_current ) {
+
+    ptree->ntrans_prefer_hit++;
+    
+    depth_hash  = (int)((unsigned int)(word1>>56) & 0x00ffU);
+    value_hash  = (int)((unsigned int)(word1>>40) & 0xffffU) - 32768;
+    move_hash   = (unsigned int)(word1>>21) & 0x7ffffU;
+    hand_hash   = (unsigned int)word1 & 0x1fffffU;
+    
+    utemp           = (unsigned int)word2;
+    state_node_hash = utemp & node_mate_threat;
+    turn_hash       = (int)((utemp>>6) & 0x1U);
+    type_hash       = (int)((utemp>>3) & 0x3U);
+    
+    if ( abs(value_hash) > score_max_eval )
+      {
+       if ( value_hash > 0 ) { value_hash -= ply-1; }
+       else                  { value_hash += ply-1; }
+#if ! defined(MINIMUM)
+       if ( abs(value_hash) > score_mate1ply )
+         {
+           out_warning( "Hash value is out of bounce!!" );
+         }
+#endif
+      }
+    
+    if ( move_hash )
+      {
+       move_hash |= turn_current ? Cap2Move( BOARD[I2To(move_hash)])
+                                  : Cap2Move(-BOARD[I2To(move_hash)]);
+      }
+
+    if ( turn_hash == turn_current && hand_hash == HAND_B ) {
+
+      assert( ! move_hash || is_move_valid( ptree, move_hash, turn_current ) );
+      ptree->amove_hash[ply] = move_hash;
+
+      if ( type_hash == value_lower
+          && value_hash >= beta
+          && ( depth_hash >= depth_current || value_hash > score_max_eval ) )
+       {
+         HASH_VALUE = value_hash;
+         ptree->ntrans_lower++;
+         return value_lower;
+       }
+
+      if ( type_hash == value_upper
+          && value_hash <= alpha
+          && ( depth_hash >= depth_current || value_hash < -score_max_eval ) )
+       {
+         HASH_VALUE = value_hash;
+         ptree->ntrans_upper++;
+         return value_upper;
+       }
+
+      if ( type_hash == value_exact
+          && ( depth_hash >= depth_current
+               || abs(value_hash) > score_max_eval ) )
+       {
+         HASH_VALUE = value_hash;
+         ptree->ntrans_upper++;
+         return value_exact;
+       }
+
+      if ( ( type_hash & flag_value_low_exact )
+          && ! ptree->nsuc_check[ply]
+          && ! ptree->nsuc_check[ply-1]
+          && ( ( depth_current < 2*PLY_INC
+                 && beta+EFUTIL_MG1 <= value_hash )
+               || ( depth_current < 3*PLY_INC
+                    && beta+EFUTIL_MG2 <= value_hash ) ) )
+       {
+         HASH_VALUE = beta;
+         ptree->ntrans_lower++;
+         return value_lower;
+       }
+
+      state_node |= state_node_hash;
+      
+      if ( value_hash <= score_max_eval ) { state_node &= ~node_do_mate; }
+
+      if ( ( type_hash & flag_value_up_exact )
+          && value_hash < beta
+          && null_depth <= depth_hash )
+       {
+         state_node &= ~node_do_null;
+       }
+
+    } else {
+
+      is_superior = eval_supe( HAND_B, hand_hash, turn_current, turn_hash,
+                              &value_hash, &type_hash );
+
+      if ( is_superior == 1 ) {
+
+       if ( turn_hash == turn_current ) { move_supe = move_hash; }
+
+       if ( type_hash & flag_value_low_exact )
+         {
+           if ( ! ptree->nsuc_check[ply]
+                && ! ptree->nsuc_check[ply-1]
+                && ( ( depth_current < 2*PLY_INC
+                       && beta+EFUTIL_MG1 <= value_hash )
+                     || ( depth_current < 3*PLY_INC
+                          && beta+EFUTIL_MG2 <= value_hash ) ) )
+             {
+               HASH_VALUE = beta;
+               ptree->ntrans_lower++;
+               return value_lower;
+             }
+           
+           if ( beta <= value_hash
+                && ( depth_current <= depth_hash
+                     || score_max_eval < value_hash
+                     || ( turn_current != turn_hash
+                          && depth_hash >= null_depth
+                          && ( state_node & node_do_null ) ) ) )
+             {
+               HASH_VALUE = value_hash;
+               ptree->ntrans_superior_hit++;
+               return value_lower;
+             }
+         }
+
+      }        else {
+
+       if ( turn_hash == turn_current ) { move_infe = move_hash; }
+
+       if ( is_superior == -1 ) {
+
+         state_node |= state_node_hash;
+
+         if ( value_hash <= score_max_eval ) { state_node &= ~node_do_mate; }
+
+         if ( type_hash & flag_value_up_exact )
+           {
+             if ( value_hash <= alpha
+                  && ( depth_current <= depth_hash
+                       || value_hash < -score_max_eval ) )
+               {
+                 HASH_VALUE = value_hash;
+                 ptree->ntrans_inferior_hit++;
+                 return value_upper;
+               }
+             if ( value_hash < beta && null_depth <= depth_hash )
+               {
+                 state_node &= ~node_do_null;
+               }
+           }
+       }
+      }
+    }
+  }
+  
+  slot  = (unsigned int)HASH_KEY >> 31;
+  word1 = ptrans_table[index].always[slot].word1;
+  word2 = ptrans_table[index].always[slot].word2;
+  
+  SignKey( word2, word1 );
+  key_hash = word2 & ~(uint64_t)0x7fU;
+  
+  if ( key_hash == key_current ) {
+
+    ptree->ntrans_always_hit++;
+
+    depth_hash  = (int)((unsigned int)(word1>>56) & 0x00ffU);
+    value_hash  = (int)((unsigned int)(word1>>40) & 0xffffU) - 32768;
+    move_hash   = (unsigned int)(word1>>21) & 0x7ffffU;
+    hand_hash   = (unsigned int)word1 & 0x1fffffU;
+    
+    utemp           = (unsigned int)word2;
+    state_node_hash = utemp & node_mate_threat;
+    turn_hash       = (int)((utemp>>6) & 0x1U);
+    type_hash       = (int)((utemp>>3) & 0x3U);
+    
+    if ( abs(value_hash) > score_max_eval )
+      {
+       if ( value_hash > 0 ) { value_hash -= ply-1; }
+       else                  { value_hash += ply-1; }
+#if ! defined(MINIMUM)
+       if ( abs(value_hash) > score_mate1ply )
+         {
+           out_warning( "Hash value is out of bounce!!" );
+         }
+#endif
+      }
+    
+    if ( move_hash )
+      {
+       move_hash |= turn_current ? Cap2Move( BOARD[I2To(move_hash)])
+                                  : Cap2Move(-BOARD[I2To(move_hash)]);
+      }
+
+    if ( turn_hash == turn_current && hand_hash == HAND_B ) {
+      
+      if ( ! ptree->amove_hash[ply] )
+       {
+         assert( ! move_hash
+                 || is_move_valid( ptree, move_hash, turn_current ) );
+         ptree->amove_hash[ply] = move_hash;
+       }
+
+      if ( type_hash == value_lower
+          && value_hash >= beta
+          && ( depth_hash >= depth_current || value_hash > score_max_eval ) )
+       {
+         HASH_VALUE = value_hash;
+         ptree->ntrans_lower++;
+         return value_lower;
+       }
+
+      if ( type_hash == value_upper
+          && value_hash <= alpha
+          && ( depth_hash >= depth_current || value_hash < -score_max_eval ) )
+       {
+         HASH_VALUE = value_hash;
+         ptree->ntrans_upper++;
+         return value_upper;
+       }
+
+      if ( type_hash == value_exact
+          && ( depth_hash >= depth_current
+               || abs(value_hash) > score_max_eval ) )
+       {
+         HASH_VALUE = value_hash;
+         ptree->ntrans_upper++;
+         return value_exact;
+       }
+
+
+      if ( ( type_hash & flag_value_low_exact )
+          && ! ptree->nsuc_check[ply]
+          && ! ptree->nsuc_check[ply-1]
+          && ( ( depth_current < 2*PLY_INC
+                 && beta+EFUTIL_MG1 <= value_hash )
+               || ( depth_current < 3*PLY_INC
+                    && beta+EFUTIL_MG2 <= value_hash ) ) )
+       {
+         HASH_VALUE = beta;
+         ptree->ntrans_lower++;
+         return value_lower;
+       }
+
+      state_node |= state_node_hash;
+
+      if ( value_hash <= score_max_eval ) { state_node &= ~node_do_mate; }
+      
+      if ( ( type_hash & flag_value_up_exact )
+          && value_hash < beta
+          && null_depth <= depth_hash )
+       {
+         state_node &= ~node_do_null;
+       }
+
+    } else {
+
+       is_superior = eval_supe( HAND_B, hand_hash, turn_current, turn_hash,
+                                &value_hash, &type_hash );
+
+       if ( is_superior == 1 ) {
+
+         if ( ( turn_hash == turn_current ) && ! move_supe )
+           {
+             move_supe = move_hash;
+           }
+         
+         if ( type_hash & flag_value_low_exact )
+           {
+             if ( ! ptree->nsuc_check[ply]
+                  && ! ptree->nsuc_check[ply-1]
+                  && ( ( depth_current < 2*PLY_INC
+                         && beta+EFUTIL_MG1 <= value_hash )
+                       || ( depth_current < 3*PLY_INC
+                            && beta+EFUTIL_MG2 <= value_hash ) ) )
+               {
+                 HASH_VALUE = beta;
+                 ptree->ntrans_lower++;
+                 return value_lower;
+               }
+             
+             if ( value_hash >= beta
+                  && ( depth_hash >= depth_current
+                       || score_max_eval < value_hash
+                       || ( turn_current != turn_hash
+                            && depth_hash >= null_depth
+                            && ( state_node & node_do_null ) ) ) )
+               {
+                 HASH_VALUE = value_hash;
+                 ptree->ntrans_superior_hit++;
+                 return value_lower;
+               }
+           }
+
+       } else {
+
+         if ( ! move_infe && turn_hash == turn_current )
+           {
+             move_infe = move_hash;
+           }
+
+         if ( is_superior == -1 ) {
+
+           state_node |= state_node_hash;
+           
+           if ( value_hash <= score_max_eval ) { state_node &= ~node_do_mate;}
+
+           if ( type_hash & flag_value_up_exact )
+             {
+               if ( value_hash <= alpha
+                    && ( depth_hash >= depth_current
+                         || value_hash < -score_max_eval ) )
+                 {
+                   HASH_VALUE = value_hash;
+                   ptree->ntrans_inferior_hit++;
+                   return value_upper;
+                 }
+               if ( value_hash < beta && null_depth <= depth_hash )
+                 {
+                   state_node &= ~node_do_null;
+                 }
+             }
+         }
+       }
+    }
+  }
+  
+  if ( ! ptree->amove_hash[ply] )
+    {
+      if ( move_supe )
+       {
+         ifrom = (int)I2From(move_supe);
+         if ( ifrom >= nsquare )
+           {
+             unsigned int hand = turn_current ? HAND_W : HAND_B;
+             switch( From2Drop(ifrom) )
+               {
+               case pawn:
+                 if ( ! IsHandPawn(hand) ) {
+                   move_supe = To2Move(I2To(move_supe));
+                   if ( IsHandLance(hand) )
+                     {
+                       move_supe |= Drop2Move(lance);
+                     }
+                   else if ( IsHandSilver(hand))
+                     {
+                       move_supe |= Drop2Move(silver);
+                     }
+                   else if ( IsHandGold(hand) )
+                     {
+                       move_supe |= Drop2Move(gold);
+                     }
+                   else { move_supe |= Drop2Move(rook); }
+                 }
+                 break;
+               
+               case lance:
+                 if ( ! IsHandLance(hand) )
+                   {
+                     move_supe = To2Move(I2To(move_supe)) | Drop2Move(rook);
+                   }
+                 break;
+               }
+           }
+
+         assert( is_move_valid( ptree, move_supe, turn_current ) );
+         ptree->amove_hash[ply] = move_supe;
+       }
+      else if ( move_infe )
+       {
+         ifrom = (int)I2From(move_infe);
+         if ( ifrom >= nsquare )
+           {
+             unsigned int hand = turn_current ? HAND_W : HAND_B;
+             switch( From2Drop(ifrom) )
+               {
+               case pawn:   if ( ! IsHandPawn(hand) )   { goto esc; } break;
+               case lance:  if ( ! IsHandLance(hand) )  { goto esc; } break;
+               case knight: if ( ! IsHandKnight(hand) ) { goto esc; } break;
+               case silver: if ( ! IsHandSilver(hand) ) { goto esc; } break;
+               case gold:   if ( ! IsHandGold(hand) )   { goto esc; } break;
+               case bishop: if ( ! IsHandBishop(hand) ) { goto esc; } break;
+               case rook:   if ( ! IsHandRook(hand) )   { goto esc; } break;
+               }
+           }
+         assert( is_move_valid( ptree, move_infe, turn_current ) );
+         ptree->amove_hash[ply] = move_infe;
+       }
+    }
+  
+ esc:
+  return state_node;
+}
+
+
+int
+hash_learn_on( void )
+{
+  int iret = file_close( pf_hash );
+  if ( iret < 0 ) { return iret; }
+
+  pf_hash = file_open( str_hash, "rb+" );
+  if ( pf_hash == NULL ) { return -2; }
+
+  return 1;
+}
+
+
+int
+hash_learn_off( void )
+{
+  int iret = file_close( pf_hash );
+  if ( iret < 0 ) { return iret; }
+
+  pf_hash = NULL;
+
+  return 1;
+}
+
+#if !defined(MINIMUM)
+int
+hash_learn_create( void )
+{
+  uint64_t au64[2];
+  unsigned int u;
+  int iret, i;
+
+  iret = hash_learn_off();
+  if ( iret < 0 ) { return iret; }
+
+  pf_hash = file_open( str_hash, "wb" );
+  if ( pf_hash == NULL ) { return -2; }
+
+  for ( i = 0; i < 5; i++ )
+    {
+      u = 0;
+      if ( fwrite( &u, sizeof(unsigned int), 1, pf_hash ) != 1 )
+       {
+         str_error = str_io_error;
+         return -2;
+       }
+    }
+
+  u = 0;
+  au64[0] = au64[1] = 0;
+  for ( i = 1; i < 0x10000; i++ )
+    if ( fwrite( &u, sizeof(unsigned int), 1, pf_hash ) != 1
+        || fwrite( au64, sizeof(uint64_t), 2, pf_hash ) != 2 )
+      {
+       str_error = str_io_error;
+       return -2;
+      }
+
+  return hash_learn_on();
+}
+#endif
+
+int
+hash_learn( const tree_t * restrict ptree, unsigned int move, int value,
+           int depth )
+{
+  trans_entry_t trans_entry;
+  unsigned int unum, unext, u;
+  int pre_value, ply;
+
+  ply = record_game.moves;
+  if ( ply >= HASH_REG_HIST_LEN )    { return 1; }
+  if ( pf_hash == NULL )             { return 1; }
+  if ( abs(value) > score_max_eval ) { return 1; }
+  if ( ply < 2 )                     { return 1; }
+  if ( depth < 2 )                   { return 1; }
+
+  if ( history_book_learn[ply].key_probed == (unsigned int)HASH_KEY
+       && history_book_learn[ply].hand_probed == HAND_B
+       && history_book_learn[ply].move_probed == move ) { return 1; }
+
+  if ( history_book_learn[ply-2].key_responsible
+       != history_book_learn[ply-2].key_played ) { return 1; }
+  if ( history_book_learn[ply-2].hand_responsible
+       != history_book_learn[ply-2].hand_played ) { return 1; }
+  if ( history_book_learn[ply-2].move_responsible
+       != history_book_learn[ply-2].move_played ) { return 1; }
+
+  if ( ( history_book_learn[ply-2].key_probed
+        == history_book_learn[ply-2].key_played )
+       && ( history_book_learn[ply-2].hand_probed
+           == history_book_learn[ply-2].hand_played )
+       && ( history_book_learn[ply-2].move_probed
+           == history_book_learn[ply-2].move_played ) ) { return 1; }
+         
+  pre_value = (int)( history_book_learn[ply-2].data & 0xffffU ) - 32768;
+
+  if ( pre_value < value + HASH_REG_MINDIFF ) { return 1; }
+  if ( pre_value < -HASH_REG_THRESHOLD )      { return 1; }
+  if ( pre_value == score_inferior )          { return 1; }
+
+  Out( "save hash value of the position\n\n" );
+  if ( fseek( pf_hash, 0, SEEK_SET ) == EOF
+       || fread( &unum,  sizeof(unsigned int), 1, pf_hash ) != 1
+       || fread( &unext, sizeof(unsigned int), 1, pf_hash ) != 1 )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  if ( ++unum  == 0x10000U ) { unum  = 0xffffU; }
+  if ( ++unext == 0x10000U ) { unext = 0x0001U; }
+
+  if ( fseek( pf_hash, 0, SEEK_SET ) == EOF
+       || fwrite( &unum,  sizeof(unsigned int), 1, pf_hash ) != 1
+       || fwrite( &unext, sizeof(unsigned int), 1, pf_hash ) != 1 )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  trans_entry
+    = hash_learn_store( ptree, depth * PLY_INC + PLY_INC/2, value, move );
+  u = (unsigned int)HASH_KEY;
+  if ( fseek( pf_hash, (long)( 20 * unext ), SEEK_SET ) == EOF
+       || fwrite( &u, sizeof(unsigned int), 1, pf_hash ) != 1
+       || fwrite( &trans_entry.word1, sizeof(uint64_t), 1, pf_hash ) != 1
+       || fwrite( &trans_entry.word2, sizeof(uint64_t), 1, pf_hash ) != 1
+       || fflush( pf_hash ) == EOF )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  
+  return 1;
+}
+
+
+static int
+eval_supe( unsigned int hand_current, unsigned int hand_hash,
+          int turn_current, int turn_hash,
+          int * restrict pvalue_hash, int * restrict ptype_hash )
+{
+  int is_superior;
+
+  if ( hand_current == hand_hash ) { is_superior = 0; }
+  else if ( is_hand_eq_supe( hand_current, hand_hash ) )
+    {
+      is_superior = turn_current ? -1 : 1;
+    }
+  else if ( is_hand_eq_supe( hand_hash, hand_current ) )
+    {
+      is_superior = turn_current ? 1 : -1;
+    }
+  else { return 0; }
+  
+  if ( turn_hash != turn_current )
+    {
+      if ( is_superior == -1 ) { is_superior = 0; }
+      else {
+       is_superior   = 1;
+       *pvalue_hash *= -1;
+       switch ( *ptype_hash )
+         {
+         case value_lower:  *ptype_hash=value_upper;  break;
+         case value_upper:  *ptype_hash=value_lower;  break;
+         }
+      }
+    }
+
+  return is_superior;
+}
+
+
+int
+clear_trans_table( void )
+{
+  unsigned int elapsed_start, elapsed_end;
+  int ntrans_table, i;
+
+  if ( get_elapsed( &elapsed_start ) < 0 ) { return -1; }
+
+  Out( "cleanning the transposition table ..." );
+  
+  trans_table_age = 1;
+  ntrans_table = 1 << log2_ntrans_table;
+  for ( i = 0; i < ntrans_table; i++ )
+    {
+      ptrans_table[i].prefer.word1    = 0;
+      ptrans_table[i].prefer.word2    = 0;
+      ptrans_table[i].always[0].word1 = 0;
+      ptrans_table[i].always[0].word2 = 0;
+      ptrans_table[i].always[1].word1 = 0;
+      ptrans_table[i].always[1].word2 = 0;
+    }
+
+  if ( get_elapsed( &elapsed_end ) < 0 ) { return -1; }
+  Out( " done (%ss)\n", str_time_symple( elapsed_end - elapsed_start ) );
+
+  return 1;
+}
+
+
+void
+add_rejections_root( tree_t * restrict ptree, unsigned int move_made )
+{
+  uint64_t hash_value;
+  unsigned int * restrict pmove;
+  unsigned int *pmove_last;
+  unsigned int hash_key, hand_ply_turn;
+  int tt;
+  unsigned char hash_parent;
+
+  tt = Flip( root_turn );
+  UnMakeMove( tt, move_made, 1 );
+  hash_parent = (unsigned char)(HASH_KEY >> 32);
+
+  pmove      = ptree->amove;
+  pmove_last = GenCaptures( tt, pmove );
+  pmove_last = GenNoCaptures( tt, pmove_last );
+  pmove_last = GenCapNoProEx2( tt, pmove_last );
+  pmove_last = GenNoCapNoProEx2( tt, pmove_last );
+  pmove_last = GenDrop( tt, pmove_last );
+
+  while ( pmove != pmove_last )
+    {
+      if ( *pmove != move_made )
+       {
+         MakeMove( tt, *pmove, 1 );
+         if ( ! InCheck( tt ) )
+           {
+             hash_key      = (unsigned int)HASH_KEY & REJEC_MASK;
+             hand_ply_turn = ( HAND_B << 6 ) | 2U | (unsigned int)tt;
+             hash_value    = ( ( HASH_KEY & ~(uint64_t)0x7ffffffU )
+                               | (uint64_t)hand_ply_turn );
+             hash_rejections[hash_key].root   = hash_value;
+             hash_rejections_parent[hash_key] = hash_parent;
+           }      
+         UnMakeMove( tt, *pmove, 1 );
+       }
+      pmove++;
+    }
+
+  MakeMove( tt, move_made, 1 );
+}
+
+
+void
+sub_rejections_root( tree_t * restrict ptree, unsigned int move_made )
+{
+  unsigned int * restrict pmove;
+  unsigned int *pmove_last;
+  unsigned int hash_key;
+
+  pmove      = ptree->amove;
+  pmove_last = GenCaptures( root_turn, pmove );
+  pmove_last = GenNoCaptures( root_turn, pmove_last );
+  pmove_last = GenCapNoProEx2( root_turn, pmove_last );
+  pmove_last = GenNoCapNoProEx2( root_turn, pmove_last );
+  pmove_last = GenDrop( root_turn, pmove_last );
+
+  while ( pmove != pmove_last )
+    {
+      if ( *pmove != move_made )
+       {
+         MakeMove( root_turn, *pmove, 1 );
+         if ( ! InCheck( root_turn ) )
+           {
+             hash_key = (unsigned int)HASH_KEY & REJEC_MASK;
+
+             hash_rejections[hash_key].root   = 0;
+             hash_rejections_parent[hash_key] = 0;
+           }      
+         UnMakeMove( root_turn, *pmove, 1 );
+       }
+      pmove++;
+    }
+}
+
+
+void
+add_rejections( tree_t * restrict ptree, int turn, int ply )
+{
+  uint64_t hash_value;
+  unsigned int * restrict pmove;
+  unsigned int * restrict pmove_last;
+  unsigned int hash_key, hand_ply_turn;
+
+#if ! defined(MINIMUM)
+  if ( game_status & flag_learning ) { return; }
+#endif
+
+  pmove      = ptree->move_last[ply-1];
+  pmove_last = GenCaptures( turn, pmove );
+  pmove_last = GenNoCaptures( turn, pmove_last );
+  pmove_last = GenCapNoProEx2( turn, pmove_last );
+  pmove_last = GenNoCapNoProEx2( turn, pmove_last );
+  pmove_last = GenDrop( turn, pmove_last );
+
+  while ( pmove != pmove_last )
+    {
+      MakeMove( turn, *pmove, ply );
+      if ( ! InCheck( turn ) )
+       {
+         hash_key = (unsigned int)HASH_KEY & REJEC_MASK;
+         if ( ! (unsigned int)hash_rejections[hash_key].sibling )
+           {
+             hand_ply_turn = ( ( HAND_B << 6 ) | ( (unsigned int)ply << 1 )
+                               | (unsigned int)turn );
+             hash_value    = ( ( HASH_KEY & ~(uint64_t)0x7ffffffU )
+                               | (uint64_t)hand_ply_turn );
+             hash_rejections[hash_key].sibling = hash_value;
+#if defined(TLP)
+             tlp_rejections_slot[hash_key] = (unsigned short)
+               ( ptree->tlp_slot ^ (unsigned short)( hash_value >> 32 ) );
+#endif
+           }
+       }
+      UnMakeMove( turn, *pmove, ply );
+      pmove++;
+    }
+}
+
+
+void
+sub_rejections( tree_t * restrict ptree, int turn, int ply )
+{
+  uint64_t hash_value;
+  unsigned int * restrict pmove;
+  unsigned int * restrict pmove_last;
+  unsigned int hash_key, hand_ply_turn;
+
+#if ! defined(MINIMUM)
+  if ( game_status & flag_learning ) { return; }
+#endif
+
+  pmove      = ptree->move_last[ply-1];
+  pmove_last = GenCaptures( turn, pmove );
+  pmove_last = GenNoCaptures( turn, pmove_last );
+  pmove_last = GenCapNoProEx2( turn, pmove_last );
+  pmove_last = GenNoCapNoProEx2( turn, pmove_last );
+  pmove_last = GenDrop( turn, pmove_last );
+
+  while ( pmove != pmove_last )
+    {
+      MakeMove( turn, *pmove, ply );
+      if ( ! InCheck( turn ) )
+       {
+         hash_key      = (unsigned int)HASH_KEY & REJEC_MASK;
+         hand_ply_turn = ( ( HAND_B << 6 )
+                           | ( (unsigned int)ply << 1 )
+                           | (unsigned int)turn );
+         hash_value    = ( ( HASH_KEY & ~(uint64_t)0x7ffffffU )
+                           | (uint64_t)hand_ply_turn );
+         
+         if ( hash_rejections[hash_key].sibling == hash_value )
+           {
+             hash_rejections[hash_key].sibling = 0;
+           }
+       }
+      UnMakeMove( turn, *pmove, ply );
+      pmove++;
+    }
+}
+
+
+int
+rejections_probe( tree_t * restrict ptree, int turn, int ply )
+{
+  uint64_t value_turn, value_turn_current, value;
+  unsigned int hand_hash, hand_current, key_current;
+  int nrep, value_ply;
+  unsigned char parent_hash, parent_current;
+
+  turn               = Flip(turn);
+  hand_current       = HAND_B;
+  key_current        = (unsigned int)HASH_KEY & REJEC_MASK;
+  value_turn_current = ( HASH_KEY & ~(uint64_t)0x7ffffffU ) | (uint64_t)turn;
+
+  value = hash_rejections[key_current].root;
+  value_turn = value & ~(uint64_t)0x7fffffeU;
+  if ( value_turn == value_turn_current )
+    {
+      hand_hash = ( (unsigned int)value & 0x7ffffffU ) >> 6;
+      if ( ( turn && is_hand_eq_supe( hand_current, hand_hash ) )
+          || ( ! turn && is_hand_eq_supe( hand_hash, hand_current ) ) )
+       {
+         nrep = root_nrep + ply - 2;
+         parent_current = (unsigned char)(ptree->rep_board_list[nrep] >> 32);
+         parent_hash    = hash_rejections_parent[key_current];
+         if ( parent_hash != parent_current ) { return 1; }
+       }
+    }
+
+  value = hash_rejections[key_current].sibling;
+  value_ply = ( (int)value & 0x3eU ) >> 1;
+  if ( value_ply + 2 < ply )
+    {
+      value_turn = value & ~(uint64_t)0x7fffffeU;
+      if ( value_turn == value_turn_current )
+       {
+         hand_hash = ( (unsigned int)value & 0x7ffffffU ) >> 6;
+         if ( ( turn && is_hand_eq_supe( hand_current, hand_hash ) )
+              || ( ! turn && is_hand_eq_supe( hand_hash, hand_current ) ) )
+           {
+#if defined(TLP)
+             int slot_hash;
+             slot_hash = (int)( tlp_rejections_slot[key_current]
+                                ^ (unsigned short)( value >> 32 ) );
+             if ( tlp_is_descendant( ptree, slot_hash ) )
+               
+#endif
+               return 1;
+           }
+       }
+    }
+
+  return 0;
+}
diff --git a/ini.c b/ini.c
new file mode 100644 (file)
index 0000000..13db541
--- /dev/null
+++ b/ini.c
@@ -0,0 +1,1097 @@
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if ! defined(_WIN32)
+#  include <unistd.h>
+#endif
+#include "shogi.h"
+
+#if   defined(_MSC_VER)
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+#else
+static int first_one00( int pcs );
+static int last_one00( int pcs );
+#endif
+
+
+static void ini_check_table( void );
+static bitboard_t bb_set_mask( int isquare );
+static int load_fv( void );
+static void set_attacks( int irank, int ifilea, bitboard_t *pbb );
+static void ini_is_same( void );
+static void ini_tables( void );
+static void ini_attack_tables( void );
+static void ini_random_table( void );
+
+
+static int
+load_fv( void )
+{
+  FILE *pf;
+  size_t size;
+  int iret;
+
+  pf = file_open( str_fv, "rb" );
+  if ( pf == NULL ) { return -2; }
+
+  size = nsquare * pos_n;
+  if ( fread( pc_on_sq, sizeof(short), size, pf ) != size )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  size = nsquare * nsquare * kkp_end;
+  if ( fread( kkp, sizeof(short), size, pf ) != size )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  iret = file_close( pf );
+  if ( iret < 0 ) { return iret; }
+
+#if 0
+#  define X0 -10000
+#  define X1 +10000
+  {
+    unsigned int a[X1-X0+1];
+    int i, n, iv;
+
+    for ( i = 0; i < X1-X0+1; i++ ) { a[i] = 0; }
+    n = nsquare * pos_n;
+    for ( i = 0; i < n; i++ )
+      {
+       iv = pc_on_sq[0][i];
+       if      ( iv < X0 ) { iv = X0; }
+       else if ( iv > X1 ) { iv = X1; }
+       a[ iv - X0 ] += 1;
+      }
+
+    pf = file_open( "dist.dat", "w" );
+    if ( pf == NULL ) { return -2; }
+
+    for ( i = X0; i <= X1; i++ ) { fprintf( pf, "%d %d\n", i, a[i-X0] ); }
+
+    iret = file_close( pf );
+    if ( iret < 0 ) { return iret; }
+  }
+#  undef x0
+#  undef x1
+#endif
+
+  return 1;
+}
+
+/*
+static int
+ini_fv( void )
+{
+  FILE *pf;
+  size_t size, i;
+
+  pf = file_open( str_fv, "wb" );
+  if ( pf == NULL ) { return -2; }
+
+  size = nsquare * pos_n;
+  for ( i = 0; i < size; i++ ) { pc_on_sq[0][i] = 0; }
+  if ( fwrite( pc_on_sq, sizeof(short), size, pf ) != size )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  size = nsquare * nsquare * kkp_end;
+  for ( i = 0; i < size; i++ ) { kkp[0][0][i] = 0; }
+  if ( fwrite( kkp, sizeof(short), size, pf ) != size )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  return file_close( pf );
+}
+*/
+
+int
+ini( tree_t * restrict ptree )
+{
+  int i;
+
+  /*if ( ini_fv() < 0 ) { return -1; }*/
+  if ( load_fv() < 0 ) { return -1; }
+
+  for ( i = 0; i < 31; i++ ) { p_value[i]       = 0; }
+  for ( i = 0; i < 31; i++ ) { p_value_ex[i]    = 0; }
+  for ( i = 0; i < 15; i++ ) { benefit2promo[i] = 0; }
+  p_value[15+pawn]       = DPawn;
+  p_value[15+lance]      = DLance;
+  p_value[15+knight]     = DKnight;
+  p_value[15+silver]     = DSilver;
+  p_value[15+gold]       = DGold;
+  p_value[15+bishop]     = DBishop;
+  p_value[15+rook]       = DRook;
+  p_value[15+king]       = DKing;
+  p_value[15+pro_pawn]   = DProPawn;
+  p_value[15+pro_lance]  = DProLance;
+  p_value[15+pro_knight] = DProKnight;
+  p_value[15+pro_silver] = DProSilver;
+  p_value[15+horse]      = DHorse;
+  p_value[15+dragon]     = DDragon;
+
+  game_status           = 0;
+  str_buffer_cmdline[0] = '\0';
+  ptrans_table_orig     = NULL;
+  record_game.pf        = NULL;
+  node_per_second       = TIME_CHECK_MIN_NODE;
+  node_limit            = UINT64_MAX;
+  time_response         = TIME_RESPONSE;
+  sec_limit             = 0;
+  sec_limit_up          = 10U;
+  sec_limit_depth       = UINT_MAX;
+  depth_limit           = PLY_MAX;
+  log2_ntrans_table     = 20;
+  
+  pf_book               = NULL;
+  pf_hash               = NULL;
+
+#if defined(TLP)
+  tlp_max        = 1;
+  tlp_abort      = 0;
+  tlp_num        = 0;
+  tlp_idle       = 0;
+  tlp_atree_work[0].tlp_id           = 0;
+  tlp_atree_work[0].tlp_abort        = 0;
+  tlp_atree_work[0].tlp_used         = 1;
+  tlp_atree_work[0].tlp_slot         = 0;
+  tlp_atree_work[0].tlp_nsibling     = 0;
+  if ( lock_init( &tlp_atree_work[0].tlp_lock ) < 0 ) { return -1; }
+  if ( lock_init( &tlp_lock )                   < 0 ) { return -1; }
+  for ( i = 0; i < tlp_max; i++ )
+    {
+      tlp_atree_work->tlp_ptrees_sibling[i] = NULL;
+    }
+  for ( i = 1; i < TLP_NUM_WORK; i++ )
+    {
+      tlp_atree_work[i].tlp_slot = (unsigned short)i;
+      tlp_atree_work[i].tlp_used = 0;
+      if ( lock_init( &tlp_atree_work[i].tlp_lock ) < 0 ) { return -1; }
+    }
+#  if defined(_WIN32)
+#  else
+  if ( pthread_attr_init( &pthread_attr )
+       || pthread_attr_setdetachstate( &pthread_attr,
+                                      PTHREAD_CREATE_DETACHED ) )
+    {
+      str_error = "pthread_attr_init() failed.";
+      return -1;
+    }
+#  endif
+#endif
+
+#if defined(CSA_LAN)
+  sckt_csa       = SCKT_NULL;
+  time_last_send = 0U;
+#endif
+
+#if defined(MNJ_LAN)
+  for ( i = 1; i < MNJ_MASK + 1; i++ ) { mnj_tbl[i] = 0; }
+  sckt_mnj       = SCKT_NULL;
+  mnj_posi_id    = 0;
+  mnj_move_last  = 0;
+  time_last_send = 0U;
+#endif
+
+#if defined(_WIN32)
+#  if defined(DEKUNOBOU)
+  dek_ngame = 0;
+#  endif
+#else
+  clk_tck = (clock_t)sysconf(_SC_CLK_TCK);
+#endif
+
+#if ! defined(NO_LOGGING)
+  pf_log = NULL;
+#endif
+
+#if   defined(_MSC_VER)
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+#else
+  for ( i = 0; i < 0x200; i++ )
+    {
+      aifirst_one[i] = (unsigned char)first_one00(i);
+      ailast_one[i]  = (unsigned char)last_one00(i);
+    }
+#endif
+  
+  for ( i = 0; i < HASH_REG_HIST_LEN; i++ )
+    {
+      history_book_learn[i].move_responsible = 0;
+      history_book_learn[i].move_probed      = 0;
+      history_book_learn[i].move_played      = 0;
+    }
+
+  ini_rand( 5489U );
+  ini_is_same();
+  ini_tables();
+  ini_attack_tables();
+  ini_random_table();
+  ini_check_table();
+
+  set_derivative_param();
+
+  if ( ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL ) < 0 )
+    {
+      return -1;
+    }
+
+  OutCsaShogi( "%s\n", str_myname );
+  Out( "%s\n", str_myname );
+
+  if ( ini_trans_table() < 0 ) { return -1; }
+
+  if ( book_on() < 0 ) { out_warning( "%s", str_error );}
+  else                 { Out( "%s found\n", str_book );}
+
+  if ( hash_learn_on() < 0 ) { out_warning( "%s", str_error );}
+  else                       { Out( "%s found\n", str_hash );}
+
+  if ( get_elapsed( &time_turn_start ) < 0 ) { return -1; }
+
+  ini_rand( time_turn_start );
+  Out( "rand seed = %x\n", time_turn_start );
+
+  resign_threshold = RESIGN_THRESHOLD;
+
+#if defined(MPV)
+  mpv_num   = 1;
+  mpv_width = 2 * MT_CAP_PAWN;
+#endif
+
+  return 1;
+}
+
+
+int
+fin( void )
+{
+#if defined(TLP)
+  int i;
+#endif
+
+  memory_free( (void *)ptrans_table_orig );
+
+#if defined(TLP)
+  tlp_abort = 1;
+  while ( tlp_num ) { tlp_yield(); }
+  if ( lock_free( &tlp_atree_work[0].tlp_lock ) < 0 ) { return -1; }
+  if ( lock_free( &tlp_lock )                   < 0 ) { return -1; }
+  for ( i = 1; i < TLP_NUM_WORK; i++ )
+    {
+      if ( lock_free( &tlp_atree_work[i].tlp_lock ) < 0 ) { return -1; }
+    }
+#  if defined(_WIN32)
+#  else
+  if ( pthread_attr_destroy( &pthread_attr ) )
+    {
+      str_error = "pthread_attr_destroy() failed.";
+      return -1;
+    }
+#  endif
+#endif
+
+  if ( book_off() < 0 ) { return -1; }
+  if ( record_close( &record_game ) < 0 ) { return -1; }
+#if ! defined(NO_LOGGING)
+  if ( file_close( pf_log ) < 0 ) { return -1; }
+#endif
+
+  return 1;
+}
+
+
+void
+set_derivative_param( void )
+{
+  p_value_ex[15+pawn]       = p_value[15+pawn]       + p_value[15+pawn];
+  p_value_ex[15+lance]      = p_value[15+lance]      + p_value[15+lance];
+  p_value_ex[15+knight]     = p_value[15+knight]     + p_value[15+knight];
+  p_value_ex[15+silver]     = p_value[15+silver]     + p_value[15+silver];
+  p_value_ex[15+gold]       = p_value[15+gold]       + p_value[15+gold];
+  p_value_ex[15+bishop]     = p_value[15+bishop]     + p_value[15+bishop];
+  p_value_ex[15+rook]       = p_value[15+rook]       + p_value[15+rook];
+  p_value_ex[15+king]       = p_value[15+king]       + p_value[15+king];
+  p_value_ex[15+pro_pawn]   = p_value[15+pro_pawn]   + p_value[15+pawn];
+  p_value_ex[15+pro_lance]  = p_value[15+pro_lance]  + p_value[15+lance];
+  p_value_ex[15+pro_knight] = p_value[15+pro_knight] + p_value[15+knight];
+  p_value_ex[15+pro_silver] = p_value[15+pro_silver] + p_value[15+silver];
+  p_value_ex[15+horse]      = p_value[15+horse]      + p_value[15+bishop];
+  p_value_ex[15+dragon]     = p_value[15+dragon]     + p_value[15+rook];
+
+  benefit2promo[7+pawn]     = p_value[15+pro_pawn]   - p_value[15+pawn];
+  benefit2promo[7+lance]    = p_value[15+pro_lance]  - p_value[15+lance];
+  benefit2promo[7+knight]   = p_value[15+pro_knight] - p_value[15+knight];
+  benefit2promo[7+silver]   = p_value[15+pro_silver] - p_value[15+silver];
+  benefit2promo[7+bishop]   = p_value[15+horse]      - p_value[15+bishop];
+  benefit2promo[7+rook]     = p_value[15+dragon]     - p_value[15+rook];
+
+  p_value[15-pawn]          = p_value[15+pawn];
+  p_value[15-lance]         = p_value[15+lance];
+  p_value[15-knight]        = p_value[15+knight];
+  p_value[15-silver]        = p_value[15+silver];
+  p_value[15-gold]          = p_value[15+gold];
+  p_value[15-bishop]        = p_value[15+bishop];
+  p_value[15-rook]          = p_value[15+rook];
+  p_value[15-king]          = p_value[15+king];
+  p_value[15-pro_pawn]      = p_value[15+pro_pawn];
+  p_value[15-pro_lance]     = p_value[15+pro_lance];
+  p_value[15-pro_knight]    = p_value[15+pro_knight];
+  p_value[15-pro_silver]    = p_value[15+pro_silver];
+  p_value[15-horse]         = p_value[15+horse];
+  p_value[15-dragon]        = p_value[15+dragon];
+
+  p_value_ex[15-pawn]       = p_value_ex[15+pawn];
+  p_value_ex[15-lance]      = p_value_ex[15+lance];
+  p_value_ex[15-knight]     = p_value_ex[15+knight];
+  p_value_ex[15-silver]     = p_value_ex[15+silver];
+  p_value_ex[15-gold]       = p_value_ex[15+gold];
+  p_value_ex[15-bishop]     = p_value_ex[15+bishop];
+  p_value_ex[15-rook]       = p_value_ex[15+rook];
+  p_value_ex[15-king]       = p_value_ex[15+king];
+  p_value_ex[15-pro_pawn]   = p_value_ex[15+pro_pawn];
+  p_value_ex[15-pro_lance]  = p_value_ex[15+pro_lance];
+  p_value_ex[15-pro_knight] = p_value_ex[15+pro_knight];
+  p_value_ex[15-pro_silver] = p_value_ex[15+pro_silver];
+  p_value_ex[15-horse]      = p_value_ex[15+horse];
+  p_value_ex[15-dragon]     = p_value_ex[15+dragon];
+
+  benefit2promo[7-pawn]     = benefit2promo[7+pawn];
+  benefit2promo[7-lance]    = benefit2promo[7+lance];
+  benefit2promo[7-knight]   = benefit2promo[7+knight];
+  benefit2promo[7-silver]   = benefit2promo[7+silver];
+  benefit2promo[7-bishop]   = benefit2promo[7+bishop];
+  benefit2promo[7-rook]     = benefit2promo[7+rook];
+}
+
+
+static void
+ini_is_same( void )
+{
+  int p[16], i, j;
+
+  for ( i = 0; i < 16; i++ ) { p[i] = 0; }
+
+  p[pawn]       =  1;
+  p[lance]      =  3;
+  p[pro_pawn]   =  3;
+  p[knight]     =  3;
+  p[pro_lance]  =  3;
+  p[pro_knight] =  3;
+  p[silver]     =  4;
+  p[pro_silver] =  4;
+  p[gold]       =  5;
+  p[bishop]     =  6;
+  p[horse]      =  7;
+  p[rook]       =  7;
+  p[dragon]     =  8;
+  p[king]       = 99;
+
+  for ( i = 0; i < 16; i++ )
+    for ( j = 0; j < 16; j++ )
+      {
+       if      ( p[i] < p[j]-1 ) { is_same[i][j] = 2U; }
+       else if ( p[i] > p[j]+1 ) { is_same[i][j] = 1U; }
+       else                      { is_same[i][j] = 0U; }
+      }
+}
+
+
+static void
+ini_tables( void )
+{
+  const unsigned char aini_rl90[] = { A1, A2, A3, A4, A5, A6, A7, A8, A9,
+                                     B1, B2, B3, B4, B5, B6, B7, B8, B9,
+                                     C1, C2, C3, C4, C5, C6, C7, C8, C9,
+                                     D1, D2, D3, D4, D5, D6, D7, D8, D9,
+                                     E1, E2, E3, E4, E5, E6, E7, E8, E9,
+                                     F1, F2, F3, F4, F5, F6, F7, F8, F9,
+                                     G1, G2, G3, G4, G5, G6, G7, G8, G9,
+                                     H1, H2, H3, H4, H5, H6, H7, H8, H9,
+                                     I1, I2, I3, I4, I5, I6, I7, I8, I9 };
+  
+  const unsigned char aini_rl45[] = { A9, B1, C2, D3, E4, F5, G6, H7, I8,
+                                     A8, B9, C1, D2, E3, F4, G5, H6, I7,
+                                     A7, B8, C9, D1, E2, F3, G4, H5, I6,
+                                     A6, B7, C8, D9, E1, F2, G3, H4, I5,
+                                     A5, B6, C7, D8, E9, F1, G2, H3, I4,
+                                     A4, B5, C6, D7, E8, F9, G1, H2, I3,
+                                     A3, B4, C5, D6, E7, F8, G9, H1, I2,
+                                     A2, B3, C4, D5, E6, F7, G8, H9, I1,
+                                     A1, B2, C3, D4, E5, F6, G7, H8, I9 };
+  
+  const unsigned char aini_rr45[] = { I8, I7, I6, I5, I4, I3, I2, I1, I9,
+                                     H7, H6, H5, H4, H3, H2, H1, H9, H8,
+                                     G6, G5, G4, G3, G2, G1, G9, G8, G7,
+                                     F5, F4, F3, F2, F1, F9, F8, F7, F6,
+                                     E4, E3, E2, E1, E9, E8, E7, E6, E5,
+                                     D3, D2, D1, D9, D8, D7, D6, D5, D4,
+                                     C2, C1, C9, C8, C7, C6, C5, C4, C3,
+                                     B1, B9, B8, B7, B6, B5, B4, B3, B2,
+                                     A9, A8, A7, A6, A5, A4, A3, A2, A1 };
+  bitboard_t abb_plus1dir[ nsquare ];
+  bitboard_t abb_plus8dir[ nsquare ];
+  bitboard_t abb_plus9dir[ nsquare ];
+  bitboard_t abb_plus10dir[ nsquare ];
+  bitboard_t abb_minus1dir[ nsquare ];
+  bitboard_t abb_minus8dir[ nsquare ];
+  bitboard_t abb_minus9dir[ nsquare ];
+  bitboard_t abb_minus10dir[ nsquare ];
+  bitboard_t bb;
+  int isquare, i, ito, ifrom, irank, ifile;
+  int isquare_rl90, isquare_rl45, isquare_rr45;
+
+  for ( isquare = 0; isquare < nsquare; isquare++ )
+    {
+      isquare_rl90 = aini_rl90[isquare];
+      isquare_rl45 = aini_rl45[isquare];
+      isquare_rr45 = aini_rr45[isquare];
+      abb_mask[isquare]      = bb_set_mask( isquare );
+      abb_mask_rl90[isquare] = bb_set_mask( isquare_rl90 );
+      abb_mask_rl45[isquare] = bb_set_mask( isquare_rl45 );
+      abb_mask_rr45[isquare] = bb_set_mask( isquare_rr45 );
+    }
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nfile; ifile++ )
+      {
+       isquare = irank*nfile + ifile;
+       BBIni( abb_plus1dir[isquare] );
+       BBIni( abb_plus8dir[isquare] );
+       BBIni( abb_plus9dir[isquare] );
+       BBIni( abb_plus10dir[isquare] );
+       BBIni( abb_minus1dir[isquare] );
+       BBIni( abb_minus8dir[isquare] );
+       BBIni( abb_minus9dir[isquare] );
+       BBIni( abb_minus10dir[isquare] );
+       for ( i = 1; i < nfile; i++ )
+         {
+           set_attacks( irank,   ifile+i, abb_plus1dir   + isquare );
+           set_attacks( irank+i, ifile-i, abb_plus8dir   + isquare );
+           set_attacks( irank+i, ifile,   abb_plus9dir   + isquare );
+           set_attacks( irank+i, ifile+i, abb_plus10dir  + isquare );
+           set_attacks( irank,   ifile-i, abb_minus1dir  + isquare );
+           set_attacks( irank-i, ifile+i, abb_minus8dir  + isquare );
+           set_attacks( irank-i, ifile,   abb_minus9dir  + isquare );
+           set_attacks( irank-i, ifile-i, abb_minus10dir + isquare );
+         }
+      }
+
+
+  for ( isquare = 0; isquare < nsquare; isquare++ )
+    {
+      BBOr( abb_plus_rays[isquare],
+           abb_plus1dir[isquare],  abb_plus8dir[isquare] );
+      BBOr( abb_plus_rays[isquare],
+           abb_plus_rays[isquare], abb_plus9dir[isquare] );
+      BBOr( abb_plus_rays[isquare],
+           abb_plus_rays[isquare], abb_plus10dir[isquare] );
+      BBOr( abb_minus_rays[isquare],
+           abb_minus1dir[isquare],  abb_minus8dir[isquare] );
+      BBOr( abb_minus_rays[isquare],
+           abb_minus_rays[isquare], abb_minus9dir[isquare] );
+      BBOr( abb_minus_rays[isquare],
+           abb_minus_rays[isquare], abb_minus10dir[isquare] );
+    }
+
+
+  for ( ifrom = 0; ifrom < nsquare; ifrom++ )
+    {
+      for ( ito = 0; ito < nsquare; ito++ )
+       {
+         adirec[ifrom][ito] = (unsigned char)direc_misc;
+       }
+
+      BBOr( bb, abb_plus1dir[ifrom], abb_minus1dir[ifrom] );
+      while ( BBToU(bb) )
+       {
+         ito = FirstOne( bb );
+         adirec[ifrom][ito]  = (unsigned char)direc_rank;
+         Xor( ito, bb );
+       }
+      BBOr( bb, abb_plus8dir[ifrom], abb_minus8dir[ifrom] );
+      while ( BBToU(bb) )
+       {
+         ito = FirstOne( bb );
+         adirec[ifrom][ito]  = (unsigned char)direc_diag1;
+         Xor( ito, bb );
+       }
+      BBOr( bb, abb_plus9dir[ifrom], abb_minus9dir[ifrom] );
+      while ( BBToU(bb) )
+       {
+         ito = FirstOne( bb );
+         adirec[ifrom][ito]  = (unsigned char)direc_file;
+         Xor(ito,bb);
+       }
+      BBOr( bb, abb_plus10dir[ifrom], abb_minus10dir[ifrom] );
+      while ( BBToU(bb) )
+       {
+         ito = FirstOne( bb );
+         adirec[ifrom][ito]  = (unsigned char)direc_diag2;
+         Xor( ito, bb );
+       }
+    }
+
+  for ( ifrom = 0; ifrom < nsquare; ifrom++ )
+    for ( ito = 0; ito < nsquare; ito++ )
+      {
+       BBIni( abb_obstacle[ifrom][ito] );
+
+       if ( ifrom-ito > 0 ) switch ( adirec[ifrom][ito] )
+         {
+         case direc_rank:
+           BBXor( abb_obstacle[ifrom][ito],
+                  abb_minus1dir[ito+1], abb_minus1dir[ifrom] );
+           break;
+         case direc_file:
+           BBXor( abb_obstacle[ifrom][ito],
+                  abb_minus9dir[ito+9], abb_minus9dir[ifrom] );
+           break;
+         case direc_diag1:
+           BBXor( abb_obstacle[ifrom][ito],
+                  abb_minus8dir[ito+8], abb_minus8dir[ifrom] );
+           break;
+         case direc_diag2:
+           BBXor( abb_obstacle[ifrom][ito],
+                  abb_minus10dir[ito+10], abb_minus10dir[ifrom] );
+           break;
+         }
+       else switch ( adirec[ifrom][ito] )
+         {
+         case direc_rank:
+           BBXor( abb_obstacle[ifrom][ito],
+                  abb_plus1dir[ito-1], abb_plus1dir[ifrom] );
+           break;
+         case direc_file:
+           BBXor( abb_obstacle[ifrom][ito],
+                  abb_plus9dir[ito-9], abb_plus9dir[ifrom] );
+           break;
+         case direc_diag1:
+           BBXor( abb_obstacle[ifrom][ito],
+                  abb_plus8dir[ito-8], abb_plus8dir[ifrom] );
+           break;
+         case direc_diag2:
+           BBXor( abb_obstacle[ifrom][ito],
+                  abb_plus10dir[ito-10], abb_plus10dir[ifrom] );
+           break;
+         }
+      }
+}
+
+
+static void
+ini_random_table( void )
+{
+  int i;
+
+  for ( i = 0; i < nsquare; i++ )
+    {
+      b_pawn_rand[ i ]       = rand64();
+      b_lance_rand[ i ]      = rand64();
+      b_knight_rand[ i ]     = rand64();
+      b_silver_rand[ i ]     = rand64();
+      b_gold_rand[ i ]       = rand64();
+      b_bishop_rand[ i ]     = rand64();
+      b_rook_rand[ i ]       = rand64();
+      b_king_rand[ i ]       = rand64();
+      b_pro_pawn_rand[ i ]   = rand64();
+      b_pro_lance_rand[ i ]  = rand64();
+      b_pro_knight_rand[ i ] = rand64();
+      b_pro_silver_rand[ i ] = rand64();
+      b_horse_rand[ i ]      = rand64();
+      b_dragon_rand[ i ]     = rand64();
+      w_pawn_rand[ i ]       = rand64();
+      w_lance_rand[ i ]      = rand64();
+      w_knight_rand[ i ]     = rand64();
+      w_silver_rand[ i ]     = rand64();
+      w_gold_rand[ i ]       = rand64();
+      w_bishop_rand[ i ]     = rand64();
+      w_rook_rand[ i ]       = rand64();
+      w_king_rand[ i ]       = rand64();
+      w_pro_pawn_rand[ i ]   = rand64();
+      w_pro_lance_rand[ i ]  = rand64();
+      w_pro_knight_rand[ i ] = rand64();
+      w_pro_silver_rand[ i ] = rand64();
+      w_horse_rand[ i ]      = rand64();
+      w_dragon_rand[ i ]     = rand64();
+    }
+
+  for ( i = 0; i < npawn_max; i++ )
+    {
+      b_hand_pawn_rand[ i ]   = rand64();
+      w_hand_pawn_rand[ i ]   = rand64();
+    }
+
+  for ( i = 0; i < nlance_max; i++ )
+    {
+      b_hand_lance_rand[ i ]  = rand64();
+      b_hand_knight_rand[ i ] = rand64();
+      b_hand_silver_rand[ i ] = rand64();
+      b_hand_gold_rand[ i ]   = rand64();
+      w_hand_lance_rand[ i ]  = rand64();
+      w_hand_knight_rand[ i ] = rand64();
+      w_hand_silver_rand[ i ] = rand64();
+      w_hand_gold_rand[ i ]   = rand64();
+    }
+
+  for ( i = 0; i < nbishop_max; i++ )
+    {
+      b_hand_bishop_rand[ i ] = rand64();
+      b_hand_rook_rand[ i ]   = rand64();
+      w_hand_bishop_rand[ i ] = rand64();
+      w_hand_rook_rand[ i ]   = rand64();
+    }
+}
+
+
+static void
+ini_attack_tables( void )
+{
+  int irank, ifile, pcs, i;
+  bitboard_t bb;
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nfile; ifile++ )
+      {
+       BBIni(bb);
+       set_attacks( irank-1, ifile-1, &bb );
+       set_attacks( irank-1, ifile+1, &bb );
+       set_attacks( irank+1, ifile-1, &bb );
+       set_attacks( irank+1, ifile+1, &bb );
+       set_attacks( irank-1, ifile, &bb );
+       abb_b_silver_attacks[ irank*nfile + ifile ] = bb;
+
+       BBIni(bb);
+       set_attacks( irank-1, ifile-1, &bb );
+       set_attacks( irank-1, ifile+1, &bb );
+       set_attacks( irank+1, ifile-1, &bb );
+       set_attacks( irank+1, ifile+1, &bb );
+       set_attacks( irank+1, ifile,   &bb );
+       abb_w_silver_attacks[ irank*nfile + ifile ] = bb;
+
+       BBIni(bb);
+       set_attacks( irank-1, ifile-1, &bb );
+       set_attacks( irank-1, ifile+1, &bb );
+       set_attacks( irank-1, ifile,   &bb );
+       set_attacks( irank+1, ifile,   &bb );
+       set_attacks( irank,   ifile-1, &bb );
+       set_attacks( irank,   ifile+1, &bb );
+       abb_b_gold_attacks[ irank*nfile + ifile ] = bb;
+
+       BBIni(bb);
+       set_attacks( irank+1, ifile-1, &bb );
+       set_attacks( irank+1, ifile+1, &bb );
+       set_attacks( irank+1, ifile,   &bb );
+       set_attacks( irank-1, ifile,   &bb );
+       set_attacks( irank,   ifile-1, &bb );
+       set_attacks( irank,   ifile+1, &bb );
+       abb_w_gold_attacks[ irank*nfile + ifile ] = bb;
+
+       BBIni(bb);
+       set_attacks( irank+1, ifile-1, &bb );
+       set_attacks( irank+1, ifile+1, &bb );
+       set_attacks( irank+1, ifile,   &bb );
+       set_attacks( irank-1, ifile-1, &bb );
+       set_attacks( irank-1, ifile+1, &bb );
+       set_attacks( irank-1, ifile,   &bb );
+       set_attacks( irank,   ifile-1, &bb );
+       set_attacks( irank,   ifile+1, &bb );
+       abb_king_attacks[ irank*nfile + ifile ] = bb;
+      }
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nfile; ifile++ )
+      {
+       BBIni(bb);
+       set_attacks( irank-2, ifile-1, &bb );
+       set_attacks( irank-2, ifile+1, &bb );
+       abb_b_knight_attacks[ irank*nfile + ifile ] = bb;
+      }
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nfile; ifile++ )
+      {
+       BBIni(bb);
+       set_attacks( irank+2, ifile-1, &bb );
+       set_attacks( irank+2, ifile+1, &bb );
+       abb_w_knight_attacks[ irank*nfile + ifile ] = bb;
+      }
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nrank; ifile++ )
+      for ( pcs = 0; pcs < 128; pcs++ )
+       {
+         BBIni(bb);
+         for ( i = -1; irank+i >= 0; i-- )
+           {
+             set_attacks( irank+i, ifile, &bb );
+             if ( (pcs<<1) & (1 << (8-irank-i)) ) { break; }
+           }
+         for ( i = 1; irank+i <= 8; i++ )
+           {
+             set_attacks( irank+i, ifile, &bb );
+             if ( (pcs<<1) & (1 << (8-irank-i)) ) { break; }
+           }
+         abb_file_attacks[irank*nfile+ifile][pcs] = bb; 
+       }
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nrank; ifile++ )
+      for ( pcs = 0; pcs < 128; pcs++ )
+       {
+         BBIni(bb);
+         for ( i = -1; ifile+i >= 0; i-- )
+           {
+             set_attacks( irank, ifile+i, &bb );
+             if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+           }
+         for ( i = 1; ifile+i <= 8; i++ )
+           {
+             set_attacks( irank, ifile+i, &bb );
+             if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+           }
+         ai_rook_attacks_r0[irank*nfile+ifile][pcs] = bb.p[irank/3]; 
+       }
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nrank; ifile++ )
+      for ( pcs = 0; pcs < 128; pcs++ )
+       {
+         BBIni(bb);
+         if ( ifile <= irank )
+           {
+             for ( i = -1; ifile+i >= 0; i-- )
+               {
+                 set_attacks( irank+i, ifile+i, &bb );
+                 if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+               }
+             for ( i = 1; irank+i <= 8; i++ )
+               {
+                 set_attacks( irank+i, ifile+i, &bb );
+                 if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+               }
+           }  
+         else {
+           for ( i = -1; irank+i >= 0; i-- )
+             {
+               set_attacks( irank+i, ifile+i, &bb );
+               if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+             }
+           for ( i = 1; ifile+i <= 8; i++ )
+             {
+               set_attacks( irank+i, ifile+i, &bb );
+               if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+             }
+         }
+         abb_bishop_attacks_rl45[irank*nfile+ifile][pcs] = bb; 
+       }
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nrank; ifile++ )
+      for ( pcs = 0; pcs < 128; pcs++ )
+       {
+         BBIni(bb);
+         if ( ifile+irank >= 8 )
+           {
+             for ( i = -1; irank-i <= 8; i-- )
+               {
+                 set_attacks( irank-i, ifile+i, &bb );
+                 if ( (pcs<<1) & (1 << (irank-i)) ) { break; }
+               }
+             for ( i = 1; ifile+i <= 8; i++ )
+               {
+                 set_attacks( irank-i, ifile+i, &bb );
+                 if ( (pcs<<1) & (1 << (irank-i)) ) { break; }
+               }
+           }  
+         else {
+           for ( i = -1; ifile+i >= 0; i-- )
+             {
+               set_attacks( irank-i, ifile+i, &bb );
+               if ( (pcs<<1) & (1 << (irank-i)) ) { break; }
+             }
+           for ( i = 1; irank-i >= 0; i++ )
+             {
+               set_attacks( irank-i, ifile+i, &bb );
+               if ( (pcs<<1) & (1 << (irank-i)) ) { break; }
+             }
+         }
+         abb_bishop_attacks_rr45[irank*nfile+ifile][pcs] = bb; 
+       }
+
+  for ( i = 0; i < nsquare; i++ )
+    {
+      aslide[i].ir0   = (unsigned char)(i/27);
+      aslide[i].sr0   = (unsigned char)((2-(i/9)%3)*9+1);
+      aslide[i].irl90 = (unsigned char)(2-(i%9)/3);
+      aslide[i].srl90 = (unsigned char)(((i%9)%3)*9+1);
+    }
+  
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nfile; ifile++ )
+      {
+       if ( irank >= ifile )
+         {
+           aslide[ irank*nfile+ifile ].irl45
+             = (unsigned char)((irank-ifile)/3);
+           aslide[ irank*nfile+ifile ].srl45
+             = (unsigned char)((2-((irank-ifile)%3))*9+1);
+         }
+       else {
+         aslide[ irank*nfile+ifile ].irl45
+           = (unsigned char)((9+irank-ifile)/3);
+         aslide[ irank*nfile+ifile ].srl45
+           = (unsigned char)((2-((9+irank-ifile)%3))*9+1);
+       }
+      }
+
+  for ( irank = 0; irank < nrank; irank++ )
+    for ( ifile = 0; ifile < nfile; ifile++ )
+      {
+       if ( ifile+irank >= 8 )
+         {
+           aslide[ irank*nfile+ifile ].irr45
+             = (unsigned char)((irank+ifile-8)/3);
+           aslide[ irank*nfile+ifile ].srr45
+             = (unsigned char)((2-((irank+ifile-8)%3))*9+1);
+         }
+       else {
+         aslide[ irank*nfile+ifile ].irr45
+           = (unsigned char)((irank+ifile+1)/3);
+         aslide[ irank*nfile+ifile ].srr45
+           = (unsigned char)((2-((irank+ifile+1)%3))*9+1);
+       }
+      }
+}
+
+
+static void
+set_attacks( int irank, int ifile, bitboard_t *pbb )
+{
+  if ( irank >= rank1 && irank <= rank9 && ifile >= file1 && ifile <= file9 )
+    {
+      Xor( irank*nfile + ifile, *pbb );
+    }
+}
+
+
+static bitboard_t
+bb_set_mask( int isquare )
+{
+  bitboard_t bb;
+  
+  if ( isquare > 53 )
+    {
+      bb.p[0] = bb.p[1] = 0;
+      bb.p[2] = 1U << (80-isquare);
+    }
+  else if ( isquare > 26 )
+    {
+      bb.p[0] = bb.p[2] = 0;
+      bb.p[1] = 1U << (53-isquare);
+    }
+  else {
+      bb.p[1] = bb.p[2] = 0;
+      bb.p[0] = 1U << (26-isquare);
+  }
+
+  return bb;
+}
+
+
+static void
+ini_check_table( void )
+{
+  bitboard_t bb_check, bb;
+  int iking, icheck;
+
+  for ( iking = 0; iking < nsquare; iking++ )
+    {
+      /* black gold */
+      BBIni( b_chk_tbl[iking].gold );
+      bb_check = abb_w_gold_attacks[iking];
+      while ( BBToU(bb_check) )
+       {
+         icheck = LastOne( bb_check );
+         BBOr( b_chk_tbl[iking].gold, b_chk_tbl[iking].gold,
+               abb_w_gold_attacks[icheck] );
+         Xor( icheck, bb_check );
+       }
+      BBOr( bb, abb_mask[iking], abb_w_gold_attacks[iking] );
+      BBNot( bb, bb );
+      BBAnd( b_chk_tbl[iking].gold, b_chk_tbl[iking].gold, bb );
+
+      /* black silver */
+      BBIni( b_chk_tbl[iking].silver );
+      bb_check = abb_w_silver_attacks[iking];
+      while ( BBToU(bb_check) )
+       {
+         icheck = LastOne( bb_check );
+         BBOr( b_chk_tbl[iking].silver, b_chk_tbl[iking].silver,
+               abb_w_silver_attacks[icheck] );
+         Xor( icheck, bb_check );
+       }
+      bb_check.p[0] = abb_w_gold_attacks[iking].p[0];
+      while ( bb_check.p[0] )
+       {
+         icheck = last_one0( bb_check.p[0] );
+         BBOr( b_chk_tbl[iking].silver, b_chk_tbl[iking].silver,
+               abb_w_silver_attacks[icheck] );
+         bb_check.p[0] ^= abb_mask[icheck].p[0];
+       }
+      bb_check.p[1] = abb_w_gold_attacks[iking].p[1];
+      while ( bb_check.p[1] )
+       {
+         icheck = last_one1( bb_check.p[1] );
+         b_chk_tbl[iking].silver.p[0]
+           |= abb_w_silver_attacks[icheck].p[0];
+         bb_check.p[1] ^= abb_mask[icheck].p[1];
+       }
+      BBOr( bb, abb_mask[iking], abb_w_silver_attacks[iking] );
+      BBNot( bb, bb );
+      BBAnd( b_chk_tbl[iking].silver, b_chk_tbl[iking].silver, bb );
+
+      /* black knight */
+      BBIni( b_chk_tbl[iking].knight );
+      bb_check = abb_w_knight_attacks[iking];
+      while ( BBToU(bb_check) )
+       {
+         icheck = LastOne( bb_check );
+         BBOr( b_chk_tbl[iking].knight, b_chk_tbl[iking].knight,
+               abb_w_knight_attacks[icheck] );
+         Xor( icheck, bb_check );
+       }
+      bb_check.p[0] = abb_w_gold_attacks[iking].p[0];
+      while ( bb_check.p[0] )
+       {
+         icheck = last_one0( bb_check.p[0] );
+         BBOr( b_chk_tbl[iking].knight, b_chk_tbl[iking].knight,
+               abb_w_knight_attacks[icheck] );
+         bb_check.p[0] ^= abb_mask[icheck].p[0];
+       }
+
+      /* black lance */
+      if ( iking <= I3 ) {
+       BBAnd( b_chk_tbl[iking].lance, abb_plus_rays[iking+nfile],
+              abb_file_attacks[iking][0] );
+       if ( iking <= I7 && iking != A9 && iking != A8 && iking != A7 ) {
+         BBAnd( bb, abb_plus_rays[iking-1], abb_file_attacks[iking-1][0] );
+         BBOr( b_chk_tbl[iking].lance, b_chk_tbl[iking].lance, bb );
+       }
+       if ( iking <= I7 && iking != I9 && iking != I8 && iking != I7 ) {
+           BBAnd( bb, abb_plus_rays[iking+1], abb_file_attacks[iking+1][0] );
+           BBOr( b_chk_tbl[iking].lance, b_chk_tbl[iking].lance, bb );
+       }
+      } else { BBIni( b_chk_tbl[iking].lance ); }
+
+      /* white gold */
+      BBIni( w_chk_tbl[iking].gold );
+      bb_check = abb_b_gold_attacks[iking];
+      while ( BBToU(bb_check) )
+       {
+         icheck = LastOne( bb_check );
+         BBOr( w_chk_tbl[iking].gold, w_chk_tbl[iking].gold,
+               abb_b_gold_attacks[icheck] );
+         Xor( icheck, bb_check );
+       }
+      BBOr( bb, abb_mask[iking], abb_b_gold_attacks[iking] );
+      BBNot( bb, bb );
+      BBAnd( w_chk_tbl[iking].gold, w_chk_tbl[iking].gold, bb );
+
+      /* white silver */
+      BBIni( w_chk_tbl[iking].silver );
+      bb_check = abb_b_silver_attacks[iking];
+      while ( BBToU(bb_check) )
+       {
+         icheck = LastOne( bb_check );
+         BBOr( w_chk_tbl[iking].silver, w_chk_tbl[iking].silver,
+               abb_b_silver_attacks[icheck] );
+         Xor( icheck, bb_check );
+       }
+      bb_check.p[2] = abb_b_gold_attacks[iking].p[2];
+      while ( bb_check.p[2] )
+       {
+         icheck = first_one2( bb_check.p[2] );
+         BBOr( w_chk_tbl[iking].silver, w_chk_tbl[iking].silver,
+               abb_b_silver_attacks[icheck] );
+         bb_check.p[2] ^= abb_mask[icheck].p[2];
+       }
+      bb_check.p[1] = abb_b_gold_attacks[iking].p[1];
+      while ( bb_check.p[1] )
+       {
+         icheck = first_one1( bb_check.p[1] );
+         w_chk_tbl[iking].silver.p[2]
+           |= abb_b_silver_attacks[icheck].p[2];
+         bb_check.p[1] ^= abb_mask[icheck].p[1];
+       }
+      BBOr( bb, abb_mask[iking], abb_b_silver_attacks[iking] );
+      BBNot( bb, bb );
+      BBAnd( w_chk_tbl[iking].silver, w_chk_tbl[iking].silver, bb );
+
+      /* white knight */
+      BBIni( w_chk_tbl[iking].knight );
+      bb_check = abb_b_knight_attacks[iking];
+      while ( BBToU(bb_check) )
+       {
+         icheck = LastOne( bb_check );
+         BBOr( w_chk_tbl[iking].knight, w_chk_tbl[iking].knight,
+               abb_b_knight_attacks[icheck] );
+         Xor( icheck, bb_check );
+       }
+      bb_check.p[2] = abb_b_gold_attacks[iking].p[2];
+      while ( bb_check.p[2] )
+       {
+         icheck = first_one2( bb_check.p[2] );
+         BBOr( w_chk_tbl[iking].knight, w_chk_tbl[iking].knight,
+               abb_b_knight_attacks[icheck] );
+         bb_check.p[2] ^= abb_mask[icheck].p[2];
+       }
+
+      /* white lance */
+      if ( iking >= A7 ) {
+       BBAnd( w_chk_tbl[iking].lance, abb_minus_rays[iking-nfile],
+              abb_file_attacks[iking][0] );
+       if ( iking >= A3 && iking != A3 && iking != A2 && iking != A1 ) {
+         BBAnd( bb, abb_minus_rays[iking-1], abb_file_attacks[iking-1][0] );
+         BBOr( w_chk_tbl[iking].lance, w_chk_tbl[iking].lance, bb );
+       }
+       if ( iking >= A3 && iking != I3 && iking != I2 && iking != I1 ) {
+         BBAnd( bb, abb_minus_rays[iking+1], abb_file_attacks[iking+1][0] );
+         BBOr( w_chk_tbl[iking].lance, w_chk_tbl[iking].lance, bb );
+       }
+      } else { BBIni( w_chk_tbl[iking].lance ); }
+    }
+}
+
+
+#if   defined(_MSC_VER)
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+#else
+static int
+first_one00( int pcs )
+{
+  int i;
+
+  for ( i = 0; i < 9; i++ ) { if ( pcs & (1<<(8-i)) ) { break; } }
+  return i;
+}
+
+
+static int
+last_one00( int pcs )
+{
+  int i;
+
+  for ( i = 8; i >= 0; i-- ) { if ( pcs & (1<<(8-i)) ) { break; } }
+  return i;
+}
+#endif
diff --git a/io.c b/io.c
new file mode 100644 (file)
index 0000000..14f841e
--- /dev/null
+++ b/io.c
@@ -0,0 +1,772 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#if defined(_WIN32)
+#  include <io.h>
+#  include <conio.h>
+#else
+#  include <sys/time.h>
+#  include <sys/types.h>
+#  include <unistd.h>
+#endif
+#include "shogi.h"
+
+#if defined(_MSC_VER)
+#  include <Share.h>
+#  define fopen( file, mode ) _fsopen( file, mode, _SH_DENYNO )
+#endif
+
+#if defined(NO_STDOUT) || defined(WIN32_PIPE)
+static int out_board0( FILE *pf, int piece, int i, int ito, int ifrom );
+#  define OutBoard0(a,b,c,d,e,f) out_board0(a,b,c,d,e)
+#else
+static int out_board0( FILE *pf, int piece, int i, int ito, int ifrom,
+                      int is_promote );
+#  define OutBoard0(a,b,c,d,e,f) out_board0(a,b,c,d,e,f)
+#endif
+
+static int check_input_buffer( void );
+static int read_command( char **pstr_line_end );
+static void out_hand( FILE *pf, unsigned int hand, const char *str_prefix );
+static void out_hand0( FILE *pf, int n, const char *str_prefix,
+                      const char *str );
+
+#if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
+void
+out( const char *format, ... )
+{
+  va_list arg;
+  if ( game_status & flag_quiet ) { return; }
+
+#  if ! defined(NO_STDOUT)
+  va_start( arg, format );
+  vprintf( format, arg );
+  va_end( arg );
+  fflush( stdout );
+#  endif
+
+#  if ! defined(NO_LOGGING)
+  if ( ( strchr( format, '\n' ) != NULL || strchr( format, '\r' ) == NULL )
+       && pf_log != NULL )
+    {
+      va_start( arg, format );
+      vfprintf( pf_log, format, arg ); 
+      va_end( arg );
+      fflush( pf_log );
+    }
+#  endif
+}
+#endif
+
+
+#if defined(CSASHOGI)
+void
+out_csashogi( const char *format, ... )
+{
+  va_list arg;
+
+  va_start( arg, format );
+  vprintf( format, arg );
+  va_end( arg );
+
+  fflush( stdout );
+}
+#endif
+
+
+void
+out_file( FILE *pf, const char *format, ... )
+{
+  va_list arg;
+
+  if ( pf != NULL )
+    {
+      va_start( arg, format );
+      vfprintf( pf, format, arg ); 
+      va_end( arg );
+      fflush( pf );
+    }
+  
+#if ! defined(NO_LOGGING)
+  if ( pf_log != NULL )
+    {
+      va_start( arg, format );
+      vfprintf( pf_log, format, arg ); 
+      va_end( arg );
+      fflush( pf_log );
+    }
+#endif
+
+}
+
+
+void
+out_warning( const char *format, ... )
+{
+  va_list arg;
+  
+  fprintf( stderr, "\n%s", str_warning );
+  va_start( arg, format );
+  vfprintf( stderr, format, arg );
+  va_end( arg );
+  fprintf( stderr, "\n\n" );
+  fflush( stderr );
+  
+#if ! defined(NO_LOGGING)
+  if ( pf_log != NULL )
+    {
+      fprintf( pf_log, "\n%s", str_warning );
+      va_start( arg, format );
+      vfprintf( pf_log, format, arg ); 
+      va_end( arg );
+      fprintf( pf_log, "\n\n" );
+      fflush( pf_log );
+    }
+#endif
+
+}
+
+
+void
+out_error( const char *format, ... )
+{
+  va_list arg;
+  
+  fprintf( stderr, "\nERROR: " );
+  va_start( arg, format );
+  vfprintf( stderr, format, arg );
+  va_end( arg );
+  fprintf( stderr, "\n\n" );
+  fflush( stderr );
+  
+#if ! defined(NO_LOGGING)
+  if ( pf_log != NULL )
+    {
+      fprintf( pf_log, "\nERROR: " );
+      va_start( arg, format );
+      vfprintf( pf_log, format, arg );
+      va_end( arg );
+      fprintf( pf_log, "\n\n" );
+      fflush( pf_log );
+    }
+#endif
+  
+}
+
+
+FILE *
+file_open( const char *str_file, const char *str_mode )
+{
+  FILE *pf;
+
+  pf = fopen( str_file, str_mode );
+  if ( pf == NULL )
+    {
+      snprintf( str_message, SIZE_MESSAGE,
+               "%s, %s", str_fopen_error, str_file );
+      str_error = str_message;
+      return NULL;
+    }
+  
+  return pf;
+}
+
+
+int
+file_close( FILE *pf )
+{
+  if ( pf == NULL ) { return 1; }
+  if ( ferror( pf ) )
+    {
+      fclose( pf );
+      str_error = str_io_error;
+      return -2;
+    }
+  if ( fclose( pf ) )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  return 1;
+}
+
+
+void
+show_prompt( void )
+{
+  if ( game_status & flag_noprompt ) { return; }
+  
+#if defined(DEKUNOBOU)
+  if ( dek_ngame )
+    {
+      Out( "Won=%3d Lost=%3d Total=%4d/", dek_win, dek_lost, dek_ngame-1 );
+    }
+#endif
+
+  if ( game_status & flag_drawn ) { Out( "Drawn> " ); }
+  else if ( game_status & flag_mated )
+    {
+      if ( root_turn ) { Out( "Black Mated> " ); }
+      else             { Out( "White Mated> " ); }
+    }
+  else if ( game_status & flag_resigned )
+    {
+      if ( root_turn ) { Out( "White Resigned> " ); }
+      else             { Out( "Black Resigned> " ); }
+    }
+  else if ( game_status & flag_suspend )
+    {
+      if ( root_turn ) { Out( "White Suspend> " ); }
+      else             { Out( "Black Suspend> " ); }
+    }
+  else if ( root_turn ) { Out( "White %d> ", record_game.moves+1 ); }
+  else                  { Out( "Black %d> ", record_game.moves+1 ); }
+}
+
+
+int
+open_history( const char *str_name1, const char *str_name2 )
+{
+#if defined(NO_LOGGING)
+  char str_file[SIZE_FILENAME];
+  int iret;
+
+  iret = record_close( &record_game );
+  if ( iret < 0 ) { return -1; }
+
+  strncpy( str_file, "game.csa", SIZE_FILENAME-1 );
+  iret = record_open( &record_game, str_file, mode_read_write,
+                     str_name1, str_name2 );
+  if ( iret < 0 ) { return -1; }
+
+  return 1;
+#else
+  FILE *pf;
+  int i, iret;
+  char str_file[SIZE_FILENAME];
+  
+  if ( record_game.pf != NULL && ! record_game.moves )
+    {
+      record_game.str_name1[0] = '\0';
+      record_game.str_name2[0] = '\0';
+
+      if ( str_name1 )
+       {
+         strncpy( record_game.str_name1, str_name1, SIZE_PLAYERNAME-1 );
+         record_game.str_name1[SIZE_PLAYERNAME-1] = '\0';
+       }
+      
+      if ( str_name2 )
+       {
+         strncpy( record_game.str_name2, str_name2, SIZE_PLAYERNAME-1 );
+         record_game.str_name2[SIZE_PLAYERNAME-1] = '\0';
+       }
+      return 1;
+    }
+
+  iret = file_close( pf_log );
+  if ( iret < 0 ) { return -1; }
+
+  iret = record_close( &record_game );
+  if ( iret < 0 ) { return -1; }
+  
+  for ( i = 0; i < 999; i++ )
+    {
+      snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
+              str_dir_logs, i );
+      pf = file_open( str_file, "r" );
+      if ( pf == NULL ) { break; }
+      iret = file_close( pf );
+      if ( iret < 0 ) { return -1; }
+    }
+  irecord_game = i;
+
+  snprintf( str_file, SIZE_FILENAME, "%s/n%03d.log",
+           str_dir_logs, i );
+  pf_log = file_open( str_file, "w" );
+  if ( pf_log == NULL ) { return -1; }
+
+  snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
+           str_dir_logs, i );
+  iret = record_open( &record_game, str_file, mode_read_write,
+                     str_name1, str_name2 );
+  if ( iret < 0 ) { return -1; }
+
+  return 1;
+#endif
+}
+
+
+int
+out_board( const tree_t * restrict ptree, FILE *pf, unsigned int move,
+          int is_strict )
+{
+  int irank, ifile, i, iret, ito, ifrom;
+
+#if ! defined(WIN32_PIPE)
+  int is_promote;
+#endif
+
+  if ( ! is_strict && move )
+    {
+      ito        = I2To( move );
+      ifrom      = I2From( move );
+#if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
+      is_promote = I2IsPromote( move );
+#endif
+    }
+  else {
+    ito = ifrom = nsquare;
+#if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
+    is_promote = 0;
+#endif
+  }
+  
+  if ( ( game_status & flag_reverse ) && ! is_strict )
+    {
+      fprintf( pf, "          <reversed>        \n" );
+      fprintf( pf, "'  1  2  3  4  5  6  7  8  9\n" );
+
+      for ( irank = rank9; irank >= rank1; irank-- )
+       {
+         fprintf( pf, "P%d", irank + 1 );
+         
+         for ( ifile = file9; ifile >= file1; ifile-- )
+           {
+             i = irank * nfile + ifile;
+             iret = OutBoard0( pf, BOARD[i], i, ito, ifrom, is_promote );
+             if ( iret < 0 ) { return iret; }
+           }
+         fprintf( pf, "\n" );
+       }
+    }
+  else {
+    fprintf( pf, "'  9  8  7  6  5  4  3  2  1\n" );
+
+    for ( irank = rank1; irank <= rank9; irank++ )
+      {
+       fprintf( pf, "P%d", irank + 1 );
+       
+       for ( ifile = file1; ifile <= file9; ifile++ )
+         {
+           i = irank * nfile + ifile;
+           iret = OutBoard0( pf, BOARD[i], i, ito, ifrom, is_promote );
+           if ( iret < 0 ) { return iret; }
+         }
+       fprintf( pf, "\n" );
+      }
+  }
+    
+  out_hand( pf, HAND_B, "P+" );
+  out_hand( pf, HAND_W, "P-" );
+  fflush( pf );
+
+  return 1;
+}
+
+
+int
+next_cmdline( int is_wait )
+{
+  char *str_line_end;
+  size_t size;
+  int iret;
+
+  str_line_end = strchr( str_buffer_cmdline, '\n' );
+
+  if ( ! str_line_end )
+    {
+      if ( is_wait )
+       {
+         do {
+           iret = read_command( & str_line_end );
+           if ( iret < 0 ) { return iret; }
+         } while ( ! str_line_end && iret );
+         if ( ! iret )
+           {
+             game_status |= flag_quit;
+             return 1;
+           }
+       }
+      else {
+#if defined(DEKUNOBOU)
+       if ( dek_ngame )
+         {
+           iret = dek_check();
+           goto tag;
+         }
+#endif
+
+#if defined(CSA_LAN)
+       if ( sckt_csa != SCKT_NULL )
+         {
+           iret = sckt_check( sckt_csa );
+           goto tag;
+         }
+#endif
+
+#if defined(MNJ_LAN)
+       if ( sckt_mnj != SCKT_NULL )
+         {
+           iret = sckt_check( sckt_mnj );
+           goto tag;
+         }
+#endif
+       iret = check_input_buffer();
+       
+#if defined(DEKUNOBOU) || defined(CSA_LAN) || defined(MNJ_LAN)
+    tag:
+#endif
+       if ( iret <= 0 ) { return iret; }
+
+       iret = read_command( & str_line_end );
+       if ( iret < 0 ) { return iret; }
+       if ( ! iret )
+         {
+           game_status |= flag_quit;
+           return 1;
+         }
+       if ( ! str_line_end ) { return 0; }
+      }
+    }
+  
+  if ( str_line_end - str_buffer_cmdline + 1 >= SIZE_CMDLINE )
+    {
+      str_error = str_ovrflw_line;
+      memmove( str_buffer_cmdline, str_line_end + 1,
+              strlen( str_line_end + 1 ) + 1 );
+      return -2;
+    }
+  
+  size = str_line_end - str_buffer_cmdline;
+  memcpy( str_cmdline, str_buffer_cmdline, size );
+  *( str_cmdline + size ) = '\0';
+  
+#if defined(DEKUNOBOU)
+  if ( dek_ngame )
+    {
+      iret = dek_parse( str_cmdline, SIZE_CMDLINE );
+      if ( iret < 0 )
+       {
+         memmove( str_buffer_cmdline, str_line_end + 1,
+                  strlen( str_line_end + 1 ) + 1 );
+         return iret;
+       }
+    }
+#endif
+
+  if ( is_wait )
+    {
+      out_file( NULL, "%s\n", str_cmdline );
+      memmove( str_buffer_cmdline, str_line_end + 1,
+              strlen( str_line_end + 1 ) + 1 );
+    }
+
+  return 1;
+}
+
+
+static int
+#if defined(NO_STDOUT) || defined(WIN32_PIPE)
+out_board0( FILE *pf, int piece, int i, int ito, int ifrom )
+#else
+out_board0( FILE *pf, int piece, int i, int ito, int ifrom, int is_promote )
+#endif
+{
+  int ch;
+#if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
+  int iret;
+#endif
+
+  if ( piece )
+    {
+      ch = piece < 0 ? '-' : '+';
+#if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
+      if ( i == ito && pf == stdout && ! ( game_status & flag_nostress ) )
+       {
+         iret = StdoutStress( is_promote, ifrom );
+         if ( iret < 0 )
+           {
+             fprintf( pf, "\n" );
+             return iret;
+           }
+       }
+#endif
+      fprintf( pf, "%c%s", ch, astr_table_piece[ abs( piece ) ] );
+#if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
+      if ( i == ito && pf == stdout && ! ( game_status & flag_nostress ) )
+       {
+         iret = StdoutNormal();
+         if ( iret < 0 )
+           {
+             fprintf( pf, "\n" );
+             return iret;
+           }
+       }
+#endif
+    }
+  else {
+    if ( ifrom < nsquare
+        && ( ifrom == i
+             || ( adirec[ito][ifrom]
+                  && adirec[ito][ifrom] == adirec[ito][i]
+                  && ( ( ito < i && i <= ifrom )
+                       || ( ito > i && i >= ifrom ) ) ) ) )
+      {
+       fprintf( pf, "   " );
+      }
+    else { fprintf( pf, " * " ); }
+  }
+
+  return 1;
+}
+
+
+#if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
+
+void
+out_beep( void )
+{
+  if ( game_status & flag_nobeep ) { return; }
+
+#  if defined(_WIN32)
+  if ( ! MessageBeep( MB_OK ) )
+    {
+      out_warning( "Beep is not available." );
+    }
+#  else
+  printf( "\007" );
+#  endif
+}
+
+
+int
+stdout_normal( void )
+{
+#  if defined(_WIN32)
+  HANDLE hStdout;
+  WORD wAttributes;
+  
+  hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
+  if ( hStdout == INVALID_HANDLE_VALUE )
+    {
+      str_error = "GetStdHandle() faild";
+      return -1;
+    }
+
+  wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+  if ( ! SetConsoleTextAttribute( hStdout, wAttributes ) )
+    {
+      str_error = "SetConsoleTextAttribute() faild";
+      return -1;
+    }
+
+#  else
+  printf( "\033[0m" );
+#  endif
+  return 1;
+}
+
+
+int
+stdout_stress( int is_promote, int ifrom )
+{
+#  if defined(_WIN32)
+  HANDLE hStdout;
+  WORD wAttributes;
+
+  hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
+  if ( hStdout == INVALID_HANDLE_VALUE )
+    {
+      str_error = "GetStdHandle() faild";
+      return -1;
+    }
+
+  if ( is_promote )
+    {
+      wAttributes = BACKGROUND_RED | BACKGROUND_INTENSITY;
+    }
+  else if ( ifrom >= nsquare )
+    {
+      wAttributes = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
+    }
+  else {
+    wAttributes = ( BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
+                   | BACKGROUND_INTENSITY );
+  }
+  if ( ! SetConsoleTextAttribute( hStdout, wAttributes ) )
+    {
+      str_error = "SetConsoleTextAttribute() faild";
+      return -1;
+    }
+#  else
+  if      ( is_promote )       { printf( "\033[7;31m" ); }
+  else if ( ifrom >= nsquare ) { printf( "\033[7;34m" ); }
+  else                         { printf( "\033[7m" ); }
+#  endif
+
+  return 1;
+}
+
+#endif /* no NO_STDOUT and no WIN32_PIPE */
+
+
+static void
+out_hand( FILE *pf, unsigned int hand, const char *str_prefix )
+{
+  out_hand0( pf, (int)I2HandPawn(hand),   str_prefix, "00FU" );
+  out_hand0( pf, (int)I2HandLance(hand),  str_prefix, "00KY" );
+  out_hand0( pf, (int)I2HandKnight(hand), str_prefix, "00KE" );
+  out_hand0( pf, (int)I2HandSilver(hand), str_prefix, "00GI" );
+  out_hand0( pf, (int)I2HandGold(hand),   str_prefix, "00KI" );
+  out_hand0( pf, (int)I2HandBishop(hand), str_prefix, "00KA" );
+  out_hand0( pf, (int)I2HandRook(hand),   str_prefix, "00HI" );
+}
+
+
+static void
+out_hand0( FILE *pf, int n, const char *str_prefix, const char *str )
+{
+  int i;
+
+  if ( n > 0 )
+    {
+      fprintf( pf, str_prefix );
+      for ( i = 0; i < n; i++ ) { fprintf( pf, str ); }
+      fprintf( pf, "\n" );
+    }
+}
+
+
+static int
+read_command( char ** pstr_line_end )
+{
+  char *str_end;
+  int count_byte, count_cmdbuff;
+
+  count_cmdbuff = (int)strlen( str_buffer_cmdline );
+  str_end       = str_buffer_cmdline + count_cmdbuff;
+
+#if defined(DEKUNOBOU)
+  if ( dek_ngame )
+    {
+      count_byte = dek_in( str_end, SIZE_CMDLINE-1-count_cmdbuff );
+      if ( count_byte < 0 ) { return count_byte; }
+      goto tag;
+    }
+#endif
+
+#if defined(CSA_LAN)
+  if ( sckt_csa != SCKT_NULL )
+    {
+      count_byte = sckt_in( sckt_csa, str_end, SIZE_CMDLINE-1-count_cmdbuff );
+      if ( count_byte < 0 ) { return count_byte; }
+      goto tag;
+    }
+#endif
+
+#if defined(MNJ_LAN)
+  if ( sckt_mnj != SCKT_NULL )
+    {
+      count_byte = sckt_in( sckt_mnj, str_end, SIZE_CMDLINE-1-count_cmdbuff );
+      if ( count_byte < 0 ) { return count_byte; }
+      goto tag;
+    }
+#endif
+
+  do { count_byte = (int)read( 0, str_end, SIZE_CMDBUFFER-1-count_cmdbuff ); }
+  while ( count_byte < 0 && errno == EINTR );
+  
+  if ( count_byte < 0 )
+    {
+      str_error = "read() faild.";
+      return -1;
+    }
+  *( str_end + count_byte ) = '\0';
+
+#if defined(DEKUNOBOU) || defined(CSA_LAN) || defined(MNJ_LAN)
+ tag:
+#endif
+
+
+  *pstr_line_end = strchr( str_buffer_cmdline, '\n' );
+  if ( *pstr_line_end == NULL
+       && count_byte + count_cmdbuff + 1 >= SIZE_CMDLINE )
+    {
+      *str_buffer_cmdline = '\0';
+      str_error = str_ovrflw_line;
+      return -2;
+    }
+
+  return count_byte;
+}
+
+#if defined(_WIN32)
+
+static int
+check_input_buffer( void )
+{
+#  if defined(WIN32_PIPE)
+  BOOL bSuccess;
+  HANDLE hHandle;
+  DWORD dwBytesRead, dwTotalBytesAvail, dwBytesLeftThisMessage;
+  char buf[1];
+
+  hHandle = GetStdHandle( STD_INPUT_HANDLE );
+  if ( hHandle == INVALID_HANDLE_VALUE )
+    {
+      str_error = "GetStdHandle() faild.";
+      return -1;
+    }
+  bSuccess = PeekNamedPipe( hHandle, buf, 1, &dwBytesRead, &dwTotalBytesAvail,
+                           &dwBytesLeftThisMessage );
+  if ( ! bSuccess )
+    {
+      str_error = "PeekNamedPipe() faild.";
+      return -1;
+    }
+  if ( dwBytesRead ) { return 1; }
+  return 0;
+#  else
+  return _kbhit();
+#  endif
+}
+
+#else /* no _WIN32 */
+
+static int
+check_input_buffer( void )
+{
+  fd_set readfds;
+  struct timeval tv;
+  int iret;
+
+#if defined(__ICC)
+#  pragma warning(disable:279)
+#  pragma warning(disable:593)
+#  pragma warning(disable:1469)
+#endif
+
+  FD_ZERO(&readfds);
+  FD_SET(0, &readfds);
+  tv.tv_sec  = 0;
+  tv.tv_usec = 0;
+  iret       = select( 1, &readfds, NULL, NULL, &tv );
+  if ( iret == -1 )
+    {
+      str_error = "select() faild.";
+      return -1;
+    }
+  return iret;
+
+#if defined(__ICC)
+#  pragma warning(default:279)
+#  pragma warning(default:593)
+#  pragma warning(default:1469)
+#endif
+}
+
+#endif /* no _WIN32 */
diff --git a/iterate.c b/iterate.c
new file mode 100644 (file)
index 0000000..d940814
--- /dev/null
+++ b/iterate.c
@@ -0,0 +1,871 @@
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+static void adjust_fmg( void );
+static int ini_hash( void );
+static int set_root_alpha( int nfail_low, int root_alpha_old );
+static int set_root_beta( int nfail_high, int root_beta_old );
+static int is_answer_right( unsigned int move );
+static const char *str_fail_high( int turn, int nfail_high );
+
+
+static int rep_book_prob( tree_t * restrict ptree )
+{
+  int i;
+
+  for ( i = root_nrep - 2; i >= 0; i -= 2 )
+    if ( ptree->rep_board_list[i] == HASH_KEY
+        && ptree->rep_hand_list[i] == HAND_B )
+      {
+       Out( "- book is ignored due to a repetition.\n" );
+       return 1;
+      }
+
+  return 0;
+}
+
+
+int
+iterate( tree_t * restrict ptree, int flag )
+{
+  int value, iret, ply, is_hash_learn_stored;
+  unsigned int cpu_start;
+  int right_answer_made;
+
+  /* probe the opening book */
+  if ( pf_book != NULL && n_nobook_move < 7 && ! rep_book_prob( ptree  ) )
+    {
+      int is_book_hit, i;
+      unsigned int elapsed;
+
+      is_book_hit = book_probe( ptree );
+      if ( is_book_hit < 0 ) { return is_book_hit; }
+
+      iret = get_elapsed( &elapsed );
+      if ( iret < 0 ) { return iret; }
+
+      Out( "- opening book is probed. (%ss)\n",
+          str_time_symple( elapsed - time_start ) );
+      if ( is_book_hit )
+       {
+         pv_close( ptree, 2, book_hit );
+         last_pv         = ptree->pv[1];
+         last_root_value = 0;
+         n_nobook_move   = 0;
+         if ( ! ( game_status & flag_puzzling ) )
+           {
+             for ( i = 0; i < HIST_SIZE; i++ )
+               {
+                 ptree->hist_good[i]  /= 256U;
+                 ptree->hist_tried[i] /= 256U;
+               }
+           }
+
+         MnjOut( "pid=%d move=%s v=0b n=0 confident\n", mnj_posi_id,
+                 str_CSA_move(ptree->pv[1].a[1]) );
+
+         return 1;
+       }
+      if ( ! ( game_status & ( flag_puzzling | flag_pondering ) ) )
+       {
+         n_nobook_move += 1;
+       }
+    }
+
+  /* initialize variables */
+  if ( get_cputime( &cpu_start ) < 0 ) { return -1; }
+
+  ptree->node_searched         =  0;
+  ptree->nreject_done          =  0;
+  ptree->nreject_tried         =  0;
+  ptree->null_pruning_done     =  0;
+  ptree->null_pruning_tried    =  0;
+  ptree->check_extension_done  =  0;
+  ptree->recap_extension_done  =  0;
+  ptree->onerp_extension_done  =  0;
+  ptree->nfour_fold_rep        =  0;
+  ptree->nperpetual_check      =  0;
+  ptree->nsuperior_rep         =  0;
+  ptree->nrep_tried            =  0;
+  ptree->neval_called          =  0;
+  ptree->nquies_called         =  0;
+  ptree->ntrans_always_hit     =  0;
+  ptree->ntrans_prefer_hit     =  0;
+  ptree->ntrans_probe          =  0;
+  ptree->ntrans_exact          =  0;
+  ptree->ntrans_lower          =  0;
+  ptree->ntrans_upper          =  0;
+  ptree->ntrans_superior_hit   =  0;
+  ptree->ntrans_inferior_hit   =  0;
+  ptree->fail_high             =  0;
+  ptree->fail_high_first       =  0;
+  ptree->current_move[0]       =  0;
+  ptree->pv[0].a[0]            =  0;
+  ptree->pv[0].a[1]            =  0;
+  ptree->pv[0].depth           =  0;
+  ptree->pv[0].length          =  0;
+  iteration_depth              =  0;
+  easy_value                   =  0;
+  easy_abs                     =  0;
+  right_answer_made            =  0;
+  is_hash_learn_stored         =  0;
+  root_abort                   =  0;
+  root_nmove                   =  0;
+  root_value                   = -score_bound;
+  root_alpha                   = -score_bound;
+  root_beta                    =  score_bound;
+  root_move_cap                =  0;
+  node_last_check              =  0;
+  time_last_eff_search         =  time_start;
+  time_last_check              =  time_start;
+  game_status                 &= ~( flag_move_now | flag_suspend
+                                   | flag_quit_ponder | flag_search_error );
+#if defined(DBG_EASY)
+  easy_move                    =  0;
+#endif
+
+#if defined(TLP)
+  ptree->tlp_abort             = 0;
+  tlp_nsplit                   = 0;
+  tlp_nabort                   = 0;
+  tlp_nslot                    = 0;
+#endif
+
+#if defined(MPV)
+  if ( ! ( game_status & flag_puzzling ) && mpv_num > 1 )
+    {
+      int i;
+
+      for ( i = 0; i < 2*mpv_num+1; i++ ) { mpv_pv[i].length = 0; }
+      
+      last_pv.a[0]    = 0;
+      last_pv.a[1]    = 0;
+      last_pv.depth   = 0;
+      last_pv.length  = 0;
+      last_root_value = 0;
+
+      root_mpv = 1;
+    }
+  else { root_mpv = 0; }
+#endif
+
+
+  for ( ply = 0; ply < PLY_MAX; ply++ )
+    {
+      ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2 = 0U;
+      ptree->killers[ply].no1 = ptree->killers[ply].no2 = 0x0U;
+    }
+
+  {
+    unsigned int u =  node_per_second / 16U;
+    if      ( u > TIME_CHECK_MAX_NODE ) { u = TIME_CHECK_MAX_NODE; }
+    else if ( u < TIME_CHECK_MIN_NODE ) { u = TIME_CHECK_MIN_NODE; }
+    node_next_signal = u;
+  }
+
+  set_search_limit_time( root_turn );
+  adjust_fmg();
+
+  /* look up last pv. */
+  if ( last_pv.length )
+    {
+      Out( "- a pv was found in the previous search result.\n" );
+
+      iteration_depth   = last_pv.depth;
+      ptree->pv[0]      = last_pv;
+      ptree->pv[0].type = prev_solution;
+      root_value        = root_turn ? -last_root_value : last_root_value;
+      out_pv( ptree, root_value, root_turn, 0 );
+      Out( "\n" );
+    }
+
+  /* probe the transposition table, since last pv is not available.  */
+  if ( ! last_pv.length
+#if defined(MPV)
+       && ! root_mpv
+#endif
+       )
+    {
+      unsigned int value_type;
+      int alpha, beta;
+    
+      iret = ini_hash();
+      if ( iret < 0 ) { return iret; }
+      is_hash_learn_stored = 1;
+
+      value = INT_MIN;
+      for ( ply = 1; ply < PLY_MAX - 10; ply++ )
+       {
+         alpha = -score_bound;
+         beta  =  score_bound;
+         
+         value_type = hash_probe( ptree, 1, ply*PLY_INC+PLY_INC/2,
+                                  root_turn, alpha, beta, 0 );
+         if ( value_type != value_exact )   { break; }
+         value = HASH_VALUE;
+      }
+      
+      if ( -score_bound < value )
+       {
+         Out( "- a pv was peeked through the transposition table.\n" );
+         iteration_depth     = ply-1;
+         ptree->pv[0].depth  = (unsigned char)(ply-1);
+         ptree->pv[0].type   = hash_hit;
+         root_value          = value;
+         out_pv( ptree, value, root_turn, 0 );
+         Out( "\n" );
+         
+         if ( ! ptree->pv[0].length )
+           {
+             iteration_depth         = 0;
+             ptree->pv[0].depth = 0;
+             root_value              = -score_bound;
+#if ! defined(MINIMUM)
+             out_warning( "PEEK FAILED!!!" );
+#endif
+           }
+       }
+    }
+
+  /* root move generation */
+  {
+    unsigned int elapsed;
+    
+    Out( "- root move generation" );
+    value = make_root_move_list( ptree, flag );
+    if ( game_status & flag_search_error ) { return -1; }
+    if ( game_status & ( flag_quit | flag_quit_ponder | flag_suspend ) )
+      {
+       return 1;
+      }
+
+    if ( ! root_nmove )
+      {
+       str_error = "No legal moves to search";
+       return -2;
+      }
+
+    if ( ! ptree->pv[0].length || ptree->pv[0].a[1] != root_move_list[0].move )
+      {
+       iteration_depth     = 0;
+       ptree->pv[0].a[1]   = root_move_list[0].move;
+       ptree->pv[0].length = 1;
+       ptree->pv[0].depth  = 1;
+       ptree->pv[0].type   = no_rep;
+       root_value          = value;
+      }
+
+#if defined(MPV)
+    if ( root_mpv )
+      {
+       if ( root_nmove == 1 ) { root_mpv = 0; }
+       easy_abs = 0;
+      }
+#endif
+
+    if ( get_elapsed( &elapsed ) < 0 ) { return -1; }
+    Out( " ... done (%d moves, %ss)\n",
+        root_nmove, str_time_symple( elapsed - time_start ) );
+  }
+
+
+  /* save preliminary result */
+  assert( root_value != -score_bound );
+  last_root_value = root_turn ? -root_value : root_value;
+  last_pv         = ptree->pv[0];
+
+#if defined(MNJ_LAN)
+  if ( sckt_mnj != SCKT_NULL )
+    {
+      const char *str = ( root_nmove == 1 ) ? "confident" : "";
+
+      MnjOut( "pid=%d move=%s v=%de n=%" PRIu64 " %s\n",
+             mnj_posi_id, str_CSA_move(ptree->pv[0].a[1]), root_value,
+             ptree->node_searched, str );
+    }
+#endif
+
+  /* return, if previous pv is long enough */
+  if ( abs(root_value) > score_max_eval
+       || iteration_depth >= depth_limit
+       || ( ( game_status & flag_puzzling )
+           && ( root_nmove == 1 || ptree->pv[0].depth > 4 ) ) )
+    {
+      return 1;
+    }
+
+  if ( ! is_hash_learn_stored )
+    {
+      iret = ini_hash();
+      if ( iret < 0 ) { return iret; }
+    }
+
+  /* iterative deepening search */
+#if defined(TLP)
+  iret = tlp_start();
+  if ( iret < 0 ) { return iret; }
+#endif
+  iteration_depth += 1;
+  root_beta        = set_root_beta(  0, root_value );
+  root_alpha       = set_root_alpha( 0, root_value );
+  root_value       = root_alpha;
+  add_rejections( ptree, root_turn, 1 );
+  Out( "- drive an iterative deepening search starting from depth %d\n",
+       iteration_depth );
+
+  for ( ; iteration_depth < 30/*PLY_MAX-10*/; iteration_depth++ ) {
+
+    MnjOut( "pid=%d d=%d\n", mnj_posi_id, iteration_depth );
+
+
+    if ( get_elapsed( &time_last_search ) < 0 ) { return -1; }
+    
+#if defined(MPV)
+    if ( root_mpv )
+      {
+       int i;
+       i = ( root_nmove < mpv_num ) ? root_nmove : mpv_num;
+       for ( ; i < mpv_num*2; i++ ) { mpv_pv[i].length = 0; }
+      }
+#endif
+    
+    {
+      unsigned int move;
+      int tt, i, n;
+
+      tt = root_turn;
+      for ( ply = 1; ply <= ptree->pv[0].length; ply++ )
+       {
+         move = ptree->pv[0].a[ply];
+         if ( ! is_move_valid( ptree, move, tt ) )
+           {
+#if ! defined(MINIMUM)
+             out_warning( "Old pv has an illegal move!  ply=%d, move=%s",
+                          ply, str_CSA_move(move) );
+#endif
+             break;
+           }
+         MakeMove( tt, move, ply );
+         if ( InCheck(tt) )
+           {
+#if ! defined(MINIMUM)
+             out_warning( "Old pv has an illegal evasion!  ply=%d, move=%s",
+                          ply, str_CSA_move(move) );
+#endif
+             UnMakeMove( tt, move, ply );
+             break;
+           }
+         tt = Flip(tt);
+       }
+      for ( ply--; ply > 0; ply-- )
+       {
+         tt   = Flip(tt);
+         move = ptree->pv[0].a[ply];
+         UnMakeMove( tt, move, ply );
+         hash_store_pv( ptree, move, tt );
+       }
+
+      root_nfail_high = 0;
+      root_nfail_low  = 0;
+
+      n = root_nmove;
+      root_move_list[0].status = flag_first;
+      for ( i = 1; i < n; i++ ) { root_move_list[i].status = 0; }
+    }
+
+    /*  a trial of searches  */
+    for ( ;; ) {
+      value = searchr( ptree, root_alpha, root_beta, root_turn,
+                      iteration_depth*PLY_INC + PLY_INC/2 );
+      if ( game_status & flag_search_error ) { return -1; }
+      if ( root_abort )                      { break; }
+
+      assert( abs(value) < score_foul );
+
+      if ( root_beta <= value )
+       {
+         const char *str_move;
+         const char *str;
+         double dvalue;
+         
+         root_move_list[0].status &= ~flag_searched;
+         root_move_list[0].status |= flag_failhigh;
+         dvalue = (double)( root_turn ? -root_beta : root_beta );
+
+         do { root_beta  = set_root_beta( ++root_nfail_high, root_beta ); }
+         while ( value >= root_beta );
+
+         str = str_time_symple( time_last_result - time_start );
+         if ( root_move_list[0].status & flag_first )
+           {
+             Out( "(%2d)%6s %7.2f ", iteration_depth, str, dvalue / 100.0 );
+           }
+         else { Out( "    %6s %7.2f ", str, dvalue / 100.0 ); }
+
+         str = str_fail_high( root_turn, root_nfail_high );
+
+         MnjOut( "pid=%d move=%s v=%dl n=%" PRIu64 "\n", mnj_posi_id,
+                 str_CSA_move(ptree->pv[1].a[1]), root_beta,
+                 ptree->node_searched );
+
+         str_move = str_CSA_move_plus( ptree, ptree->pv[1].a[1], 1,
+                                       root_turn );
+         Out( " 1.%c%s [%s!]\n", ach_turn[root_turn], str_move, str );
+         
+         
+         if ( game_status & flag_pondering )
+           {
+             OutCsaShogi( "info%+.2f %c%s %c%s [%s!]\n",
+                          dvalue / 100.0, ach_turn[Flip(root_turn)],
+                          str_CSA_move(ponder_move),
+                          ach_turn[root_turn], str_move, str );
+           }
+         else {
+           OutCsaShogi( "info%+.2f %c%s [%s!]\n", dvalue / 100.0,
+                        ach_turn[root_turn], str_move, str );
+         }
+       }
+      else if ( value <= root_alpha )
+       {
+         const char *str_move;
+         const char *str;
+         unsigned int time_elapsed;
+         double dvalue;
+
+         if ( ! ( root_move_list[0].status & flag_first ) )
+           {
+             root_value = root_alpha;
+             break;
+           }
+
+         root_move_list[0].status &= ~flag_searched;
+         root_move_list[0].status |= flag_faillow;
+         dvalue = (double)( root_turn ? -root_alpha : root_alpha );
+
+         if ( get_elapsed( &time_elapsed ) < 0 ) { return -1; }
+
+         do { root_alpha = set_root_alpha( ++root_nfail_low, root_alpha ); }
+         while ( value <= root_alpha );
+         root_value = root_alpha;
+         str = str_time_symple( time_elapsed - time_start );
+         Out( "(%2d)%6s %7.2f ", iteration_depth, str, dvalue / 100.0 );
+
+         str      = str_fail_high( Flip(root_turn), root_nfail_low );
+         str_move = str_CSA_move_plus( ptree, root_move_list[0].move, 1,
+                                       root_turn );
+         Out( " 1.%c%s [%s?]\n", ach_turn[root_turn], str_move, str );
+         if ( game_status & flag_pondering )
+           {
+             OutCsaShogi( "info%+.2f %c%s %c%s [%s?]\n",
+                          dvalue / 100.0, ach_turn[Flip(root_turn)],
+                          str_CSA_move(ponder_move),
+                          ach_turn[root_turn], str_move, str );
+           }
+         else {
+           OutCsaShogi( "info%+.2f %c%s [%s?]\n", dvalue / 100.0,
+                        ach_turn[root_turn], str_move, str );
+         }
+       }
+      else { break; }
+    }
+
+    /* the trial of search ended */
+    if ( root_alpha < root_value && root_value < root_beta )
+      {
+       last_root_value = root_turn ? - root_value : root_value;
+       last_pv         = ptree->pv[0];
+      }
+
+    if ( root_abort ) { break; }
+
+    if ( root_alpha < root_value && root_value < root_beta )
+      {
+#if ! defined(MINIMUM)
+       {
+         int i, n;
+         n = root_nmove;
+         for ( i = 0; i < n; i++ )
+           {
+             if ( root_move_list[i].status & flag_searched ) { continue; }
+             out_warning( "A root move %s is ignored\n",
+                          str_CSA_move(root_move_list[i].move) );
+           }
+       }
+#endif
+
+       if ( ( game_status & flag_problem ) && depth_limit == PLY_MAX )
+         {
+           if ( is_answer_right( ptree->pv[0].a[1] ) )
+             {
+               if ( right_answer_made > 1 && iteration_depth > 3 ) { break; }
+               right_answer_made++;
+             }
+           else { right_answer_made = 0; }
+         }
+       
+       if ( abs(value)      >  score_max_eval ) { break; }
+       if ( iteration_depth >= depth_limit )    { break; }
+       
+       root_beta  = set_root_beta(  0, value );
+       root_alpha = set_root_alpha( 0, value );
+       root_value = root_alpha;
+      }
+#if ! defined(MINIMUM)
+    else { out_warning(( "SEARCH INSTABILITY IS DETECTED!!!" )); }
+#endif
+
+    /* shell sort */
+    {
+      root_move_t root_move_swap;
+      const int n = root_nmove;
+      uint64_t sortv;
+      int i, j, k, h;
+      
+      for ( k = SHELL_H_LEN - 1; k >= 0; k-- )
+       {
+         h = ashell_h[k];
+         for ( i = n-h-1; i > 0; i-- )
+           {
+             root_move_swap = root_move_list[i];
+             sortv          = root_move_list[i].nodes;
+             for ( j = i+h; j < n && root_move_list[j].nodes > sortv; j += h )
+               {
+                 root_move_list[j-h] = root_move_list[j];
+               }
+             root_move_list[j-h] = root_move_swap;
+           }
+       }
+    }
+  }
+
+  /* iteration ended */
+  sub_rejections( ptree, root_turn, 1 );
+
+  if ( game_status & flag_problem )
+    {
+      if ( is_answer_right( ptree->pv[0].a[1] ) )
+       {
+         right_answer_made = 1;
+       }
+      else { right_answer_made = 0; }
+    }
+
+  {
+    int i;
+    
+    for ( i = 0; i < HIST_SIZE; i++ )
+      {
+       ptree->hist_good[i]  /= 256U;
+       ptree->hist_tried[i] /= 256U;
+      }
+  }
+  /* prunings and extentions-statistics */
+  {
+    double drep, dreject, dhash, dnull, dfh1st;
+
+    drep    = (double)ptree->nperpetual_check;
+    drep   += (double)ptree->nfour_fold_rep;
+    drep   += (double)ptree->nsuperior_rep;
+    drep   *= 100.0 / (double)( ptree->nrep_tried + 1 );
+
+    dreject  = 100.0 * (double)ptree->nreject_done;
+    dreject /= (double)( ptree->nreject_tried + 1 );
+
+    dhash   = (double)ptree->ntrans_exact;
+    dhash  += (double)ptree->ntrans_inferior_hit;
+    dhash  += (double)ptree->ntrans_superior_hit;
+    dhash  += (double)ptree->ntrans_upper;
+    dhash  += (double)ptree->ntrans_lower;
+    dhash  *= 100.0 / (double)( ptree->ntrans_probe + 1 );
+
+    dnull   = 100.0 * (double)ptree->null_pruning_done;
+    dnull  /= (double)( ptree->null_pruning_tried + 1 );
+
+    dfh1st  = 100.0 * (double)ptree->fail_high_first;
+    dfh1st /= (double)( ptree->fail_high + 1 );
+
+    Out( "    pruning  -> rep=%4.2f%%  reject=%4.2f%%\n", drep, dreject );
+    
+    Out( "    pruning  -> hash=%2.0f%%  null=%2.0f%%  fh1st=%4.1f%%\n",
+        dhash, dnull, dfh1st );
+    
+    Out( "    extension-> chk=%u recap=%u 1rep=%u\n",
+        ptree->check_extension_done, ptree->recap_extension_done,
+        ptree->onerp_extension_done );
+  }
+
+  /* futility threashold */
+#if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
+  {
+    int misc   = fmg_misc;
+    int drop   = fmg_drop;
+    int cap    = fmg_cap;
+    int mt     = fmg_mt;
+    int misc_k = fmg_misc_king;
+    int cap_k  = fmg_cap_king;
+    Out( "    futility -> misc=%d drop=%d cap=%d mt=%d misc(k)=%d cap(k)=%d\n",
+        misc, drop, cap, mt, misc_k, cap_k );
+  }
+#endif
+
+  /* hashing-statistics */
+  {
+    double dalways, dprefer, dsupe, dinfe;
+    double dlower, dupper, dsat;
+    uint64_t word2;
+    int ntrans_table, i, n;
+
+    ntrans_table = 1 << log2_ntrans_table;
+    if ( ntrans_table > 8192 ) { ntrans_table = 8192; }
+    
+    for ( i = 0, n = 0; i < ntrans_table; i++ )
+      {
+       word2 = ptrans_table[i].prefer.word2;
+       SignKey( word2, ptrans_table[i].prefer.word1 );
+       if ( trans_table_age == ( 7 & (int)word2 ) ) { n++; }
+
+       word2 = ptrans_table[i].always[0].word2;
+       SignKey( word2, ptrans_table[i].always[0].word1 );
+       if ( trans_table_age == ( 7 & (int)word2 ) ) { n++; }
+
+       word2 = ptrans_table[i].always[1].word2;
+       SignKey( word2, ptrans_table[i].always[1].word1 );
+       if ( trans_table_age == ( 7 & (int)word2 ) ) { n++; }
+      }
+
+    dalways  = 100.0 * (double)ptree->ntrans_always_hit;
+    dalways /= (double)( ptree->ntrans_probe + 1 );
+
+    dprefer  = 100.0 * (double)ptree->ntrans_prefer_hit;
+    dprefer /= (double)( ptree->ntrans_probe + 1 );
+
+    dsupe    = 100.0 * (double)ptree->ntrans_superior_hit;
+    dsupe   /= (double)( ptree->ntrans_probe + 1 );
+
+    dinfe    = 100.0 * (double)ptree->ntrans_inferior_hit;
+    dinfe   /= (double)( ptree->ntrans_probe + 1 );
+
+    Out( "    hashing  -> always=%2.0f%% prefer=%2.0f%% supe=%4.2f%% "
+        "infe=%4.2f%%\n", dalways, dprefer, dsupe, dinfe );
+
+    dlower  = 100.0 * (double)ptree->ntrans_lower;
+    dlower /= (double)( ptree->ntrans_probe + 1 );
+
+    dupper  = 100.0 * (double)ptree->ntrans_upper;
+    dupper /= (double)( ptree->ntrans_probe + 1 );
+
+    dsat    = 100.0 * (double)n;
+    dsat   /= (double)( 3 * ntrans_table );
+
+    OutCsaShogi( "statsatu=%.0f", dsat );
+    Out( "    hashing  -> "
+        "exact=%d lower=%2.0f%% upper=%4.2f%% sat=%2.0f%% age=%d\n",
+        ptree->ntrans_exact, dlower, dupper, dsat, trans_table_age );
+    if ( dsat > 9.0 ) { trans_table_age  = ( trans_table_age + 1 ) & 0x7; }
+  }
+
+#if defined(TLP)
+  if ( tlp_max > 1 )
+    {
+      Out( "    threading-> split=%d abort=%d slot=%d\n",
+          tlp_nsplit, tlp_nabort, tlp_nslot+1 );
+      if ( tlp_nslot+1 == TLP_NUM_WORK )
+       {
+         out_warning( "THREAD WORK AREA IS USED UP!!!" );
+       }
+    }
+#endif
+
+  {
+    double dcpu_percent, dnps, dmat;
+    unsigned int cpu, elapsed;
+
+    Out( "    n=%" PRIu64 " quies=%u eval=%u rep=%u %u(chk) %u(supe)\n",
+        ptree->node_searched, ptree->nquies_called, ptree->neval_called,
+        ptree->nfour_fold_rep, ptree->nperpetual_check,
+        ptree->nsuperior_rep );
+
+    if ( get_cputime( &cpu )     < 0 ) { return -1; }
+    if ( get_elapsed( &elapsed ) < 0 ) { return -1; }
+
+    cpu             -= cpu_start;
+    elapsed         -= time_start;
+
+    dcpu_percent     = 100.0 * (double)cpu;
+    dcpu_percent    /= (double)( elapsed + 1U );
+
+    dnps             = 1000.0 * (double)ptree->node_searched;
+    dnps            /= (double)( elapsed + 1U );
+
+#if defined(TLP)
+    {
+      double n = (double)tlp_max;
+      node_per_second  = (unsigned int)( ( dnps + 0.5 ) / n );
+    }
+#else
+    node_per_second  = (unsigned int)( dnps + 0.5 );
+#endif
+
+    dmat             = (double)MATERIAL;
+    dmat            /= (double)MT_CAP_PAWN;
+
+    OutCsaShogi( " cpu=%.0f nps=%.2f\n", dcpu_percent, dnps / 1e3 );
+    Out( "    time=%s  ", str_time_symple( elapsed ) );
+    Out( "cpu=%3.0f%%  mat=%.1f  nps=%.2fK", dcpu_percent, dmat, dnps / 1e3 );
+    Out( "  time_eff=%s\n\n",
+        str_time_symple( time_last_eff_search - time_start ) );
+  }
+
+  if ( ( game_status & flag_problem ) && ! right_answer_made ) { iret = 0; }
+  else                                                         { iret = 1; }
+
+  return iret;
+}
+
+
+static int
+ini_hash( void )
+{
+  unsigned int elapsed;
+  int iret;
+
+  if ( time_limit < 150U ) { return 1; }
+  
+  iret = all_hash_learn_store();
+  if ( iret < 0 ) { return iret; }
+  if ( iret )
+    {
+      if ( get_elapsed( &elapsed ) < 0 ) { return -1; }
+      Out( "- load learnt hash values (%ss)\n",
+          str_time_symple( elapsed - time_start ) );
+    }
+
+  return 1;
+}
+
+
+static void
+adjust_fmg( void )
+{
+  int misc, cap, drop, mt, misc_king, cap_king;
+
+  misc      = fmg_misc      - FMG_MG      / 2;
+  cap       = fmg_cap       - FMG_MG      / 2;
+  drop      = fmg_drop      - FMG_MG      / 2;
+  misc_king = fmg_misc_king - FMG_MG_KING / 2;
+  cap_king  = fmg_cap_king  - FMG_MG_KING / 2;
+  mt        = fmg_mt        - FMG_MG_MT   / 2;
+
+  fmg_misc      = ( misc      < FMG_MISC      ) ? FMG_MISC      : misc;
+  fmg_cap       = ( cap       < FMG_CAP       ) ? FMG_CAP       : cap;
+  fmg_drop      = ( drop      < FMG_DROP      ) ? FMG_DROP      : drop;
+  fmg_misc_king = ( misc_king < FMG_MISC_KING ) ? FMG_MISC_KING : misc_king;
+  fmg_cap_king  = ( cap_king  < FMG_CAP_KING  ) ? FMG_CAP_KING  : cap_king;
+  fmg_mt        = ( mt        < FMG_MT        ) ? FMG_MT        : mt;
+}
+
+
+static int
+set_root_beta( int nfail_high, int root_beta_old )
+{
+  int aspiration_hwdth, aspiration_fail1;
+
+  if ( time_max_limit != time_limit )
+    {
+      aspiration_hwdth = MT_CAP_DRAGON / 8;
+      aspiration_fail1 = MT_CAP_DRAGON / 2;
+    }
+  else {
+    aspiration_hwdth = MT_CAP_DRAGON / 4;
+    aspiration_fail1 = ( MT_CAP_DRAGON * 3 ) / 4;
+  }
+
+  switch ( nfail_high )
+    {
+    case 0:  root_beta_old += aspiration_hwdth;                     break;
+    case 1:  root_beta_old += aspiration_fail1 - aspiration_hwdth;  break;
+    case 2:  root_beta_old  = score_bound;                          break;
+    default:
+      out_error( "Error at set_root_beta!" );
+      exit(1);
+    }
+  if ( root_beta_old > score_max_eval ) { root_beta_old = score_bound; }
+
+  return root_beta_old;
+}
+
+
+static int
+set_root_alpha( int nfail_low, int root_alpha_old )
+{
+  int aspiration_hwdth, aspiration_fail1;
+
+  if ( time_max_limit != time_limit )
+    {
+      aspiration_hwdth = MT_CAP_DRAGON / 8;
+      aspiration_fail1 = MT_CAP_DRAGON / 2;
+    }
+  else {
+    aspiration_hwdth = MT_CAP_DRAGON / 4;
+    aspiration_fail1 = ( MT_CAP_DRAGON * 3 ) / 4;
+  }
+
+  switch ( nfail_low )
+    {
+    case 0:  root_alpha_old -= aspiration_hwdth;                     break;
+    case 1:  root_alpha_old -= aspiration_fail1 - aspiration_hwdth;  break;
+    case 2:  root_alpha_old  = -score_bound;                         break;
+    default:
+      out_error( "Error at set_root_alpha!" );
+      exit(1);
+    }
+  if ( root_alpha_old < -score_max_eval ) { root_alpha_old = -score_bound; }
+
+  return root_alpha_old;
+}
+
+
+static const char *
+str_fail_high( int turn, int nfail_high )
+{
+  const char *str;
+
+  if ( time_max_limit != time_limit )
+    {
+      if ( nfail_high == 1 ) { str = turn ? "-1" : "+1"; }
+      else                   { str = turn ? "-4" : "+4"; }
+    }
+  else {
+    if ( nfail_high == 1 ) { str = turn ? "-2" : "+2"; }
+    else                   { str = turn ? "-6" : "+6"; }
+  }
+  return str;
+}
+
+
+static int
+is_answer_right( unsigned int move )
+{
+  const char *str_anser;
+  const char *str_move;
+  int ianser, iret;
+  
+  iret     = 0;
+  str_move = str_CSA_move( move );
+
+  for ( ianser = 0; ianser < MAX_ANSWER; ianser++ )
+    {
+      str_anser = &( record_problems.info.str_move[ianser][0] );
+      if ( str_anser[0] == '\0' ) { break; }
+      if ( ! strcmp( str_anser+1, str_move ) )
+       {
+         iret = 1;
+         break;
+       }
+    }
+
+  return iret;
+}
diff --git a/lan.txt b/lan.txt
new file mode 100644 (file)
index 0000000..680470d
--- /dev/null
+++ b/lan.txt
@@ -0,0 +1,30 @@
+# 'book narrow' allows Bonanza to play only famous opening-lines.
+# Use this only when Bonanza plays a small number of games.
+book wide
+# book narrow
+
+# Set the time control to 15 minutes - 0 second, limit of depth to 18.
+limit time 15 0 18
+
+# Set the time margin to 200 miliseconds.
+time response 200
+
+# In the case of this example, Bonanza uses two threads to search the
+# best move.
+tlp num 2
+
+# Do pondering.
+ponder on
+
+# Set the size of the transposition table to 192 MBytes.
+hash 22
+
+# Set the resign threashold to 65535 if you do not want Bonanza resigns.
+resign 1500
+# resign 65535
+
+# connect "hostname" "port #" "login id" "login password" "num games"
+connect wdoor.c.u-tokyo.ac.jp 4081 YourID floodgate-900-0,Something 999
+
+# quit Bonanza.
+quit
diff --git a/learn1.c b/learn1.c
new file mode 100644 (file)
index 0000000..a52ed68
--- /dev/null
+++ b/learn1.c
@@ -0,0 +1,1074 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+#if defined(_WIN32)
+#  include <process.h>
+#else
+#  include <sched.h>
+#endif
+#include "shogi.h"
+
+#if ! defined(MINIMUM)
+
+#  define SEARCH_DEPTH      2
+#  define NUM_RESULT        8
+#  define MAX_RECORD_LENGTH 1024
+#  define DOT_INTERVAL      10
+#  define MAX_BOOK_PLY      64
+#  define NumBookCluster    256
+#  define NumBookEntry      0x1000
+#  define SIZE_PV_BUFFER    0x100000
+#  define MOVE_VOID         0x80000000U
+#  define Move2S(move)      (unsigned short)((move) & 0x7fffU)
+
+
+typedef struct {
+  struct { uint64_t a,b; } cluster[NumBookCluster];
+} book_entry_t;
+
+typedef struct {
+
+  /* input */
+  tree_t *ptree;
+  book_entry_t *pbook_entry;
+  FILE *pf_tmp;
+  record_t *precord;
+  unsigned int max_games, id;
+  int nworker;
+
+  /* output */
+  uint64_t result[ NUM_RESULT ];
+  uint64_t num_moves_counted, num_moves, result_norm, num_nodes;
+  double target, target_out_window;
+  unsigned int illegal_moves, max_pos_buf;
+  int info;
+
+  /* work area */
+  unsigned int record_moves[ MAX_RECORD_LENGTH ];
+  unsigned int amove_legal[ MAX_LEGAL_MOVES ];
+  unsigned int record_length, pos_buf;
+  unsigned short buf[ SIZE_PV_BUFFER ];
+  int root_turn;
+
+} parse1_data_t;
+
+typedef struct {
+
+  /* input */
+  tree_t *ptree;
+  FILE *pf_tmp;
+  unsigned int id;
+  int nworker;
+
+  /* output */
+  param_t param;
+  uint64_t num_moves_counted;
+  double target;
+  int info;
+
+  /* work area */
+  unsigned short buf[ SIZE_PV_BUFFER ];
+  unsigned int pv[ PLY_MAX + 2 ];
+
+} parse2_data_t;
+
+#  if defined(_WIN32)
+static unsigned int __stdcall parse1_worker( void *arg );
+static unsigned int __stdcall parse2_worker( void *arg );
+#  else
+static void *parse1_worker( void *arg );
+static void *parse2_worker( void *arg );
+#endif
+static void ini_book( book_entry_t *pbook_entry );
+static void make_pv( parse1_data_t *pdata, unsigned int record_move );
+static int read_game( parse1_data_t *pdata );
+static int read_buf( unsigned short *buf, FILE *pf );
+static int calc_deriv( parse2_data_t *pdata, int pos_buf, int turn );
+static int learn_parse1( tree_t * restrict ptree, book_entry_t *pbook_entry,
+                        FILE *pf_tmp, record_t *precord,
+                        unsigned int max_games, double *ptarget_out_window,
+                        double *pobj_norm, int tlp1 );
+static int learn_parse2( tree_t * restrict ptree, FILE *pf_tmp,
+                        int nsteps, double target_out_window,
+                        double obj_norm, int tlp2 );
+static int book_probe_learn( const tree_t * restrict ptree,
+                            book_entry_t *pbook_entry, int ply,
+                            unsigned int move );
+static int rep_check_learn( tree_t * restrict ptree, int ply );
+static unsigned int s2move( const tree_t * restrict ptree, unsigned int move,
+                           int tt );
+static double func( double x );
+static double dfunc( double x );
+
+int
+learn( tree_t * restrict ptree, int is_ini, int nsteps, unsigned int max_games,
+       int max_iterations, int nworker1, int nworker2 )
+{
+  record_t record;
+  book_entry_t *pbook_entry;
+  FILE *pf_tmp;
+  double target_out_window, obj_norm;
+  int iret, niterations;
+
+  pbook_entry = memory_alloc( sizeof(book_entry_t) * NumBookEntry );
+  if ( pbook_entry == NULL ) { return -2; }
+
+  if ( is_ini )
+    {
+      fill_param_zero();
+      fmg_misc      = fmg_cap      = fmg_drop = fmg_mt = 0;
+      fmg_misc_king = fmg_cap_king = 0;
+    }
+  else {
+    fmg_misc      = FMG_MISC;
+    fmg_cap       = FMG_CAP;
+    fmg_drop      = FMG_DROP;
+    fmg_mt        = FMG_MT;
+    fmg_misc_king = FMG_MISC_KING;
+    fmg_cap_king  = FMG_CAP_KING;
+  }
+
+  game_status     |= flag_learning;
+  root_alpha       = - ( score_max_eval + 1 );
+  root_beta        = + ( score_max_eval + 1 );
+  root_abort       = 0;
+  iret             = 1;
+
+  for ( niterations = 1; niterations <= max_iterations; niterations++ )
+    {
+      Out( "\n  Iteration %03d\n", niterations );
+
+      iret = record_open( &record, "records.csa", mode_read, NULL, NULL );
+      if ( iret < 0 ) { break; }
+  
+      pf_tmp = file_open( "tmp.bin", "wb" );
+      if ( pf_tmp == NULL )
+       {
+         record_close( &record );
+         iret = -2;
+         break;
+       }
+
+      iret = learn_parse1( ptree, pbook_entry, pf_tmp, &record, max_games,
+                          &target_out_window, &obj_norm, nworker1 );
+
+      if ( iret < 0 )
+       {
+         record_close( &record );
+         file_close( pf_tmp );
+         break;
+       }
+
+      iret = file_close( pf_tmp );
+      if ( iret < 0 )
+       {
+         record_close( &record );
+         break;
+       }
+
+      pf_tmp = file_open( "tmp.bin", "rb" );
+      if ( pf_tmp == NULL )
+       {
+         record_close( &record );
+         iret = -2;
+         break;
+       }
+
+      iret = learn_parse2( ptree, pf_tmp, nsteps, target_out_window, obj_norm,
+                          nworker2 );
+      if ( iret < 0 )
+       {
+         file_close( pf_tmp );
+         record_close( &record );
+         break;
+       }
+
+      iret = file_close( pf_tmp );
+      if ( iret < 0 )
+       {
+         record_close( &record );
+         break;
+       }
+
+      iret = record_close( &record );
+      if ( iret < 0 ) { break; }
+
+      if ( ! ( game_status & flag_learning ) )
+       {
+         out_warning( "flag_learning is not set." );
+       }
+    }
+  
+  memory_free( pbook_entry );
+  game_status &= ~flag_learning;
+  
+  return iret;
+}
+
+
+static int
+learn_parse1( tree_t * restrict ptree, book_entry_t *pbook_entry, FILE *pf_tmp,
+             record_t *precord, unsigned int max_games,
+             double *ptarget_out_window, double *pobj_norm, int nworker )
+{
+  parse1_data_t *pdata[ TLP_MAX_THREADS ];
+  int i, id;
+
+  ini_book( pbook_entry );
+
+  for ( id = 0; id < nworker; id++ )
+    {
+      pdata[id] = memory_alloc( sizeof(parse1_data_t) );
+      if ( pdata[id] == NULL ) { return -1; }
+
+      pdata[id]->ptree       = NULL;
+      pdata[id]->pbook_entry = pbook_entry;
+      pdata[id]->pf_tmp      = pf_tmp;
+      pdata[id]->precord     = precord;
+      pdata[id]->max_games   = max_games;
+      pdata[id]->id          = id;
+      pdata[id]->nworker     = nworker;
+    }
+
+#if defined(TLP)
+  for ( id = 1; id < nworker; id++ )
+    {
+#  if defined(_WIN32)
+      pdata[id]->ptree = tlp_atree_work + id;
+      if ( ! _beginthreadex( 0, 0, parse1_worker, pdata[id], 0, 0 ) )
+       {
+         str_error = "_beginthreadex() failed.";
+         return -1;
+       }
+#  else
+      pthread_t pt;
+
+      pdata[id]->ptree = tlp_atree_work + id;
+      if ( pthread_create( &pt, &pthread_attr, parse1_worker, pdata[id] ) )
+       {
+         str_error = "pthread_create() failed.";
+         return -1;
+       }
+#  endif
+    }
+#endif /* TLP */
+
+  pdata[0]->ptree = ptree;
+  parse1_worker( pdata[0] );
+
+#if defined(TLP)
+  while ( tlp_num ) { tlp_yield(); }
+#endif
+  
+  for ( id = 0; id < nworker; id++ )
+    {
+      if ( pdata[id]->info < 0 ) { return -1; }
+    }
+
+  for ( id = 1; id < nworker; id++ )
+    {
+      for ( i = 0; i < NUM_RESULT; i++ )
+       {
+         pdata[0]->result[i] += pdata[id]->result[i];
+       }
+      pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
+      pdata[0]->num_moves         += pdata[id]->num_moves;
+      pdata[0]->num_nodes         += pdata[id]->num_nodes;
+      pdata[0]->result_norm       += pdata[id]->result_norm;
+      pdata[0]->target            += pdata[id]->target;
+      pdata[0]->target_out_window += pdata[id]->target_out_window;
+      pdata[0]->illegal_moves     += pdata[id]->illegal_moves;
+      if ( pdata[0]->max_pos_buf < pdata[id]->max_pos_buf )
+       {
+         pdata[0]->max_pos_buf = pdata[id]->max_pos_buf;
+       }
+    }
+  if ( pdata[0]->result_norm == 0 ) { pdata[0]->result_norm = 1; }
+  if ( pdata[0]->num_moves   == 0 ) { pdata[0]->num_moves   = 1; }
+  *ptarget_out_window = pdata[0]->target_out_window;
+  *pobj_norm          = (double)pdata[0]->num_moves;
+
+  {
+    double dtemp;
+    int misc, drop, cap, mt, misc_king, cap_king;
+
+    Out( " done\n" );
+    Out( "   Number of Games : %u\n",       precord->games );
+    Out( "   Total Moves     : %"PRIu64"\n",pdata[0]->num_moves );
+    Out( "   Moves Counted   : %"PRIu64"\n",pdata[0]->num_moves_counted);
+    Out( "   Illegal Moves   : %u\n",       pdata[0]->illegal_moves );
+    Out( "   Nodes Searched  : %"PRIu64"\n",pdata[0]->num_nodes );
+    Out( "   Max pos_buf     : %x\n",       pdata[0]->max_pos_buf );
+    Out( "   Move Prediction :" );
+    for ( i = 0, dtemp = 0.0; i < NUM_RESULT; i++ )
+      {
+       dtemp += (double)pdata[0]->result[i] * 100.0;
+       Out( " %4.1f%%", dtemp / (double)pdata[0]->result_norm );
+      }
+    Out( "\n" );
+  
+    pdata[0]->target /= *pobj_norm;
+    dtemp             = *ptarget_out_window / *pobj_norm;
+    Out( "   Target          : %f (%f)\n", pdata[0]->target, dtemp );
+
+    misc      = fmg_misc      / 2;
+    drop      = fmg_drop      / 2;
+    cap       = fmg_cap       / 2;
+    mt        = fmg_mt        / 2;
+    misc_king = fmg_misc_king / 2;
+    cap_king  = fmg_cap_king  / 2;
+    Out( "   Futility        : misc=%d drop=%d cap=%d mt=%d misc(k)=%d "
+        "cap(k)=%d\n", misc, drop, cap, mt, misc_king, cap_king );
+  }
+
+  for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
+  
+  return 1;
+}
+
+
+#  if defined(_MSC_VER)
+static unsigned int __stdcall parse1_worker( void *arg )
+#  else
+static void *parse1_worker( void *arg )
+#endif
+{
+  parse1_data_t *pdata;
+  tree_t *ptree;
+  unsigned int record_move;
+  int i, imove, iret;
+
+  iret  = 0;
+  pdata = (parse1_data_t *)arg;
+  ptree = pdata->ptree;
+
+#if defined(TLP)
+  if ( pdata->nworker > 1 )
+    {
+      lock( &tlp_lock );
+      tlp_num += 1;
+      if ( pdata->id ) { Out( "hi from thread #%d\n", pdata->id ); }
+      unlock( &tlp_lock );
+      while ( tlp_num < pdata->nworker ) { tlp_yield(); }
+    }
+#endif
+
+  for ( i = 0; i < NUM_RESULT; i++ ) { pdata->result[i] = 0; }
+  pdata->num_moves_counted = 0;
+  pdata->num_moves         = 0;
+  pdata->num_nodes         = 0;
+  pdata->max_pos_buf       = 0;
+  pdata->result_norm       = 0;
+  pdata->record_length     = 0;
+  pdata->illegal_moves     = 0;
+  pdata->info              = 0;
+  pdata->target            = 0.0;
+  pdata->target_out_window = 0.0;
+
+  for ( ;; ) {
+    /* make results */
+    pdata->pos_buf = 2U;
+    for ( imove = 0; imove < (int)pdata->record_length; imove++ )
+      {
+       record_move                    = pdata->record_moves[imove];
+
+       pdata->buf[ pdata->pos_buf++ ] = Move2S(record_move);
+
+       if ( record_move & MOVE_VOID ) { record_move &= ~MOVE_VOID; }
+       else                           { make_pv( pdata, record_move ); }
+
+       pdata->buf[ pdata->pos_buf++ ] = 0;
+
+       MakeMove( pdata->root_turn, record_move, 1 );
+       pdata->root_turn     = Flip( pdata->root_turn );
+       ptree->move_last[1]  = ptree->move_last[0];
+       ptree->nsuc_check[0] = 0;
+       ptree->nsuc_check[1]
+         = (unsigned char)( InCheck( pdata->root_turn ) ? 1U : 0 );
+      }
+
+#if defined(TLP)
+    if ( pdata->nworker > 1 ) { lock( &tlp_lock ); }
+#endif
+
+    /* save results */
+    if ( pdata->record_length )
+      {
+       if ( pdata->pos_buf > pdata->max_pos_buf )
+         {
+           pdata->max_pos_buf = pdata->pos_buf;
+         }
+       pdata->buf[0] = (unsigned short)( pdata->pos_buf / 0x10000U );
+       pdata->buf[1] = (unsigned short)( pdata->pos_buf % 0x10000U );
+
+       if ( fwrite( pdata->buf, sizeof(unsigned short), pdata->pos_buf,
+                    pdata->pf_tmp ) != pdata->pos_buf )
+         {
+           str_error = str_io_error;
+           iret      = -2;
+         }
+      }
+
+    /* read next game */
+    while ( iret >= 0 ) {
+      iret = read_game( pdata );
+      if ( iret == 1 )            { break; } /* end of record */
+      if ( pdata->record_length ) { break; } /* read a record */
+    }
+    
+#if defined(TLP)
+    if ( pdata->nworker > 1 ) { unlock( &tlp_lock ); }
+#endif
+
+    if ( iret < 0 )  { break; }
+    if ( iret == 1 ) { break; }
+  }
+
+#if defined(TLP)
+  if ( pdata->nworker > 1 )
+    {
+      lock( &tlp_lock );
+      tlp_num -= 1;
+      unlock( &tlp_lock );
+    }
+#endif
+
+  pdata->info = iret;
+  return 0;
+}
+
+
+static void
+make_pv( parse1_data_t *pdata, unsigned int record_move )
+{
+  double func_value;
+  tree_t *ptree;
+  unsigned int *pmove;
+  unsigned int move, pos_buf;
+  int i, imove, record_value, nth, nc, nmove_legal;
+  int value, alpha, beta, depth, ply, tt;
+
+  record_value          = INT_MIN;
+  nc                    = 0;
+  nth                   = 0;
+  depth                 = PLY_INC * SEARCH_DEPTH + PLY_INC / 2;
+  tt                    = Flip(pdata->root_turn);
+  pos_buf               = pdata->pos_buf;
+  ptree                 = pdata->ptree;
+  ptree->node_searched  = 0;
+#if defined(TLP)
+  ptree->tlp_abort      = 0;
+#endif
+  for ( ply = 0; ply < PLY_MAX; ply++ )
+    {
+      ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2 = 0U;
+      ptree->killers[ply].no1 = ptree->killers[ply].no2 = 0U;
+    }
+  for ( i = 0; i < HIST_SIZE; i++ )
+    {
+      ptree->hist_good[i]  /= 256U;
+      ptree->hist_tried[i] /= 256U;
+    }
+    
+  pmove = GenCaptures     ( pdata->root_turn, pdata->amove_legal );
+  pmove = GenNoCaptures   ( pdata->root_turn, pmove );
+  pmove = GenDrop         ( pdata->root_turn, pmove );
+  pmove = GenCapNoProEx2  ( pdata->root_turn, pmove );
+  pmove = GenNoCapNoProEx2( pdata->root_turn, pmove );
+  nmove_legal = (int)( pmove - pdata->amove_legal );
+  
+  for ( i = 0; pdata->amove_legal[i] != record_move; i++ );
+  move                  = pdata->amove_legal[0];
+  pdata->amove_legal[0] = pdata->amove_legal[i];
+  pdata->amove_legal[i] = move;
+    
+  for ( imove = 0; imove < nmove_legal; imove++ ) {
+    move = pdata->amove_legal[imove];
+    if ( imove )
+      {
+       alpha = record_value - FV_WINDOW;
+       beta  = record_value + FV_WINDOW;
+       if ( alpha < root_alpha ) { alpha = root_alpha; }
+       if ( beta  > root_beta )  { beta  = root_beta; }
+      }
+    else {
+      alpha = root_alpha;
+      beta  = root_beta;
+    }
+
+    MakeMove( pdata->root_turn, move, 1 );
+    if ( InCheck(pdata->root_turn) )
+      {
+       UnMakeMove( pdata->root_turn, move, 1 );
+       continue;
+      }
+
+    if ( InCheck(tt) )
+      {
+       ptree->nsuc_check[2]
+         = (unsigned char)( ptree->nsuc_check[0] + 1U );
+      } else { ptree->nsuc_check[2] = 0; }
+
+    ptree->current_move[1] = move;
+    ptree->pv[1].type = no_rep;
+      
+    value = -search( ptree, -beta, -alpha, tt, depth, 2,
+                    node_do_mate | node_do_null | node_do_futile
+                    | node_do_recap );
+
+    UnMakeMove( pdata->root_turn, move, 1 );
+
+    if ( abs(value) > score_mate1ply )
+      {
+       out_warning( "value is larger than mate1ply!" );
+      }
+    
+    if ( imove )
+      {
+       func_value        = func( value - record_value );
+       pdata->target    += func_value;
+       pdata->num_moves += 1U;
+       if ( alpha < value && value < beta )
+         {
+           nc += 1;
+         }
+       else { pdata->target_out_window += func_value; }
+       if ( value >= record_value ) { nth += 1; }
+      }
+    else if ( alpha < value && value < beta )
+      {
+       nth          += 1;
+       record_value  = value;
+      }
+    else { break; } /* record move failed high or low. */
+
+    if ( alpha < value && value < beta )
+      {
+       pdata->buf[ pos_buf++ ] = Move2S(move);
+       for ( ply = 2; ply <= ptree->pv[1].length; ply++ )
+         {
+           pdata->buf[ pos_buf++ ] = Move2S(ptree->pv[1].a[ply]);
+         }
+       pdata->buf[ pos_buf - 1 ] |= 0x8000U;
+      }
+  }
+
+  if ( nth - 1 >= 0 )
+    {
+      pdata->result_norm += 1;
+      if ( nth-1 < NUM_RESULT ) { pdata->result[nth-1] += 1; }
+    }
+
+  if ( nc )
+    {
+      pdata->pos_buf            = pos_buf;
+      pdata->num_moves_counted += nc;
+    }
+  pdata->num_nodes += ptree->node_searched;
+}
+
+
+static int
+read_game( parse1_data_t *pdata )
+{
+  tree_t *ptree;
+  tree_t tree;
+  unsigned int record_move;
+  int istatus, iret, imove;
+
+  ptree   = & tree;
+  istatus = 0;
+  if ( pdata->precord->games == pdata->max_games ) { return 1; }
+
+  if ( pdata->precord->games == 0 ) { Out( "  Parse 1 " ); }
+
+  if ( ! ( (pdata->precord->games+1) % DOT_INTERVAL ) )
+    {
+      if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 10 ) ) )
+       {
+         Out( "o" );
+         if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 50 ) ) )
+           {
+             Out( "%7d\n          ", pdata->precord->games+1 );
+           }
+       }
+      else { Out( "." ); }
+    }
+
+  for ( imove = 0; imove < MAX_RECORD_LENGTH; imove++ )
+    {
+      istatus = in_CSA( ptree, pdata->precord, &record_move,
+                       flag_nomake_move | flag_detect_hang | flag_nofmargin );
+      if ( istatus < 0 )
+       {
+         pdata->illegal_moves += 1;
+         break;
+       }
+      if ( istatus >= record_eof ) { break; }
+
+      if ( ! imove
+          && ( root_turn != min_posi_no_handicap.turn_to_move
+               || HAND_B != min_posi_no_handicap.hand_black
+               || HAND_W != min_posi_no_handicap.hand_white
+               || memcmp( BOARD, min_posi_no_handicap.asquare, nsquare ) ) )
+       {
+         break;
+       }
+      
+      if ( ! imove )
+       {
+         *(pdata->ptree)  = *ptree;
+         pdata->root_turn = root_turn;
+       }
+
+      if ( rep_check_learn( ptree, 1 ) == four_fold_rep
+          || ( pdata->precord->moves < MAX_BOOK_PLY
+               && book_probe_learn( ptree, pdata->pbook_entry,
+                                    pdata->precord->moves, record_move ) ) )
+       {
+         pdata->record_moves[ imove ] = record_move | MOVE_VOID;
+       }
+      else { pdata->record_moves[ imove ] = record_move; }
+
+      iret = make_move_root( ptree, record_move, flag_rejections );
+      if ( iret < 0 ) { return iret; }
+    }
+  
+  if ( istatus != record_next && istatus != record_eof )
+    {
+      istatus = record_wind( pdata->precord );
+      if ( istatus < 0 ) { return istatus; }
+    }
+  
+  if ( ! imove && istatus == record_eof ) { return 1; }
+  pdata->record_length = imove;
+
+  return 0;
+}
+
+
+static int
+learn_parse2( tree_t * restrict ptree, FILE *pf_tmp, int nsteps,
+             double target_out_window, double obj_norm, int nworker )
+{
+  parse2_data_t *pdata[ TLP_MAX_THREADS ];
+  int istep, id;
+
+  for ( id = 0; id < nworker; id++ )
+    {
+      pdata[id] = memory_alloc( sizeof(parse2_data_t) );
+      if ( pdata[id] == NULL ) { return -1; }
+  
+      pdata[id]->ptree   = NULL;
+      pdata[id]->pf_tmp  = pf_tmp;
+      pdata[id]->id      = id;
+      pdata[id]->nworker = nworker;
+    }
+
+  Out( "  Parse 2\n" );
+
+  istep = 0;
+  for ( ;; ) {
+
+#if defined(TLP)
+    for ( id = 1; id < nworker; id++ )
+      {
+#  if defined(_WIN32)
+       pdata[id]->ptree = tlp_atree_work + id;
+       if ( ! _beginthreadex( 0, 0, parse2_worker, pdata[id], 0, 0 ) )
+         {
+           str_error = "_beginthreadex() failed.";
+           return -1;
+         }
+#  else
+       pthread_t pt;
+       
+       pdata[id]->ptree = tlp_atree_work + id;
+       if ( pthread_create( &pt, &pthread_attr, parse2_worker, pdata[id] ) )
+         {
+           str_error = "pthread_create() failed.";
+           return -1;
+         }
+#  endif
+      }
+#endif /* TLP */
+    
+    pdata[0]->ptree = ptree;
+    parse2_worker( pdata[0] );
+
+#if defined(TLP)
+    while ( tlp_num ) { tlp_yield(); }
+#endif
+  
+    for ( id = 0; id < nworker; id++ )
+      {
+       if ( pdata[id]->info < 0 ) { return -1; }
+      }
+
+    for ( id = 1; id < nworker; id++ )
+      {
+       add_param( &pdata[0]->param, &pdata[id]->param );
+       pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
+       pdata[0]->target            += pdata[id]->target;
+      }
+
+    if ( ! istep )
+      {
+       double target, penalty, objective_function;
+
+       penalty = calc_penalty() / obj_norm;
+       target  = ( pdata[0]->target + target_out_window ) / obj_norm;
+       objective_function = target + penalty;
+       Out( "   Moves Counted   : %d\n", pdata[0]->num_moves_counted );
+       Out( "   Objective Func. : %f %f %f\n",
+                 objective_function, target, penalty );
+       Out( "   Steps " );
+      }
+
+    param_sym( &pdata[0]->param );
+
+    renovate_param( &pdata[0]->param );
+    istep += 1;
+    if ( istep < nsteps ) { Out( "." ); }
+    else {
+      Out( ". done\n\n" );
+      break;
+    }
+    rewind( pf_tmp );
+  }
+  for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
+
+  return out_param();
+}
+
+
+#  if defined(_MSC_VER)
+static unsigned int __stdcall parse2_worker( void *arg )
+#  else
+static void *parse2_worker( void *arg )
+#endif
+{
+  parse2_data_t *pdata;
+  tree_t *ptree;
+  unsigned int record_move;
+  int iret, imove, nbuf, pos_buf, turn;
+
+  iret  = 0;
+  pdata = (parse2_data_t *)arg;
+  ptree = pdata->ptree;
+
+#if defined(TLP)
+  if ( pdata->nworker > 1 )
+    {
+      lock( &tlp_lock );
+      tlp_num += 1;
+      unlock( &tlp_lock );
+      while ( tlp_num < pdata->nworker ) { tlp_yield(); }
+    }
+#endif
+  
+  pdata->num_moves_counted = 0;
+  pdata->info              = 0;
+  pdata->target            = 0.0;
+  ini_param( &pdata->param );
+
+  for ( ;; ) {
+#if defined(TLP)
+    if ( pdata->nworker > 1 ) { lock( &tlp_lock ); }
+#endif
+    iret = read_buf( pdata->buf, pdata->pf_tmp );
+#if defined(TLP)
+    if ( pdata->nworker > 1 ) { unlock( &tlp_lock ); }
+#endif
+
+    if ( iret <= 0 )  { break; } /* 0: eof, -2: error */
+    nbuf = iret;
+
+    iret = ini_game( ptree, &min_posi_no_handicap, flag_nofmargin,
+                    NULL, NULL );
+    if ( iret < 0 ) { break; }
+
+    turn    = black;
+    pos_buf = 2;
+    for ( imove = 0; pos_buf < nbuf; imove++ )
+      {
+       record_move = s2move( ptree, pdata->buf[pos_buf++], turn );
+
+       if ( pdata->buf[pos_buf] )
+         {
+           pos_buf = calc_deriv( pdata, pos_buf, turn );
+         }
+       pos_buf += 1;
+
+       MakeMove( turn, record_move, 1 );
+       turn                 = Flip( turn );
+       ptree->move_last[1]  = ptree->move_last[0];
+       ptree->nsuc_check[0] = 0;
+       ptree->nsuc_check[1]
+         = (unsigned char)( InCheck( turn ) ? 1U : 0 );
+      }
+  }
+
+#if defined(TLP)
+  if ( pdata->nworker > 1 )
+    {
+      lock( &tlp_lock );
+      tlp_num -= 1;
+      unlock( &tlp_lock );
+    }
+#endif
+
+  pdata->info = iret;
+  return 0;
+}
+
+
+static int
+read_buf( unsigned short *buf, FILE *pf )
+{
+  size_t size;
+
+  size = fread( buf, sizeof(unsigned short), 2, pf );
+  if ( ! size && feof( pf ) ) { return 0; }
+  if ( size != 2 )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  size = (size_t)buf[1] + (size_t)buf[0] * 0x10000 - 2;
+  if ( fread( buf+2, sizeof(unsigned short), size, pf ) != size )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  return (int)size;
+}
+
+
+static int
+calc_deriv( parse2_data_t *pdata, int pos0, int turn0 )
+{
+  double target, dT, sum_dT;
+  tree_t * restrict ptree;
+  const unsigned short *buf;
+  unsigned int nc;
+  int ply, turn, pv_length, pos, record_value, value;
+
+  ptree  = pdata->ptree;
+  buf    = pdata->buf;
+  nc     = 0;
+  turn   = turn0;
+  pos    = pos0;
+  target = 0.0;
+  sum_dT = 0.0;
+
+  ply  = 1;
+  for ( ;; ) {
+    pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
+    MakeMove( turn, pdata->pv[ply], ply );
+    turn = Flip( turn );
+    if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
+    ply += 1;
+  }
+  pv_length = ply;
+
+  record_value = evaluate( ptree, ply+1, turn );
+  if ( turn != turn0 ) { record_value = -record_value; }
+
+  for ( ;; ) {
+    turn  = Flip( turn );
+    UnMakeMove( turn, pdata->pv[ply], ply );
+    if ( ply == 1 ) { break; }
+    ply -= 1;
+  }
+  pos += pv_length;
+
+  while ( buf[ pos ] ) {
+    ply  = 1;
+    for ( ;; ) {
+      pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
+      MakeMove( turn, pdata->pv[ply], ply );
+      turn = Flip( turn );
+      if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
+      ply += 1;
+    }
+    pv_length = ply;
+
+    value = evaluate( ptree, ply+1, turn );
+    if ( turn != turn0 ) { value = -value; }
+    target += func( value - record_value );
+         
+    dT = dfunc( value - record_value );
+    if ( turn0 ) { dT = -dT; }
+    sum_dT += dT;
+    inc_param( ptree, &pdata->param, -dT );
+
+    for ( ;; ) {
+      turn  = Flip( turn );
+      UnMakeMove( turn, pdata->pv[ply], ply );
+      if ( ply == 1 ) { break; }
+      ply -= 1;
+    }
+
+    pos += pv_length;
+    nc  += 1;
+  }
+
+  ply  = 1;
+  for ( ;; ) {
+    pdata->pv[ply] = s2move( ptree, buf[ pos0+ply-1 ] & 0x7fffU, turn );
+    MakeMove( turn, pdata->pv[ply], ply );
+    turn = Flip( turn );
+    if ( buf[ pos0+ply-1 ] & 0x8000U ) { break; }
+    ply += 1;
+  }
+
+  inc_param( ptree, &pdata->param, sum_dT );
+
+  for ( ;; ) {
+    turn  = Flip( turn );
+    UnMakeMove( turn, pdata->pv[ply], ply );
+    if ( ply == 1 ) { break; }
+    ply -= 1;
+  }
+
+  pdata->num_moves_counted += nc;
+  pdata->target            += target;
+
+  return pos;
+}
+
+
+static double
+func( double x )
+{
+  const double delta = (double)FV_WINDOW / 7.0;
+  double d;
+  
+  if      ( x < -FV_WINDOW ) { x = -FV_WINDOW; }
+  else if ( x >  FV_WINDOW ) { x =  FV_WINDOW; }
+  d = 1.0 / ( 1.0 + exp(-x/delta) );
+
+  return d;
+}
+
+
+static double
+dfunc( double x )
+{
+  const double delta = (double)FV_WINDOW / 7.0;
+  double dd, dn, dtemp, dret;
+
+  if      ( x <= -FV_WINDOW ) { dret = 0.0; }
+  else if ( x >=  FV_WINDOW ) { dret = 0.0; }
+  else {
+    dn    = exp( - x / delta );
+    dtemp = dn + 1.0;
+    dd    = delta * dtemp * dtemp;
+    dret  = dn / dd;
+  }
+  
+  return dret;
+}
+
+
+static unsigned int
+s2move( const tree_t * restrict ptree, unsigned int move, int tt )
+{
+  int from, to;
+
+  from = I2From(move);
+  if ( from < nsquare )
+    {
+      to = I2To(move);
+      move |= tt ? (Piece2Move(-BOARD[from])|Cap2Move( BOARD[to]))
+                : (Piece2Move( BOARD[from])|Cap2Move(-BOARD[to]));
+    }
+  return move;
+}
+
+
+static void
+ini_book( book_entry_t *pbook_entry )
+{
+  int i, j;
+  
+  for ( i = 0; i < NumBookEntry; i++ )
+    for ( j = 0; j < NumBookCluster; j++ ) {
+      pbook_entry[i].cluster[j].a = (uint64_t)0;
+      pbook_entry[i].cluster[j].b = (uint64_t)0x1ffU << 41;
+    }
+}
+
+
+/*
+a: key     64   0
+
+b: ply      9  41
+   move    19  22
+   turn     1  21
+   hand    21   0
+*/
+static int
+book_probe_learn( const tree_t * restrict ptree,
+                 book_entry_t *pbook_entry,
+                 int ply, unsigned int move )
+{
+  book_entry_t *p;
+  int i, j;
+
+  move &= 0x7ffffU;
+  p = pbook_entry
+    + ((unsigned int)HASH_KEY & (unsigned int)(NumBookEntry-1));
+
+  for ( i = 0; i < NumBookCluster; i++ )
+    if ( p->cluster[i].a == HASH_KEY
+        && ((unsigned int)p->cluster[i].b & 0x1fffffU) == HAND_B
+        && ( (((unsigned int)p->cluster[i].b>>21) & 0x1U)
+             == (unsigned int)root_turn )
+        && ((unsigned int)(p->cluster[i].b>>22) & 0x7ffffU) == move ) {
+      return 1;
+    }
+  
+  for ( i = 0; i < NumBookCluster; i++ )
+    if ( ( (unsigned int)( p->cluster[i].b >> 41 ) & 0x1ffU )
+        > (unsigned int)ply ) { break; }
+
+  if ( i < NumBookCluster ) {
+    for ( j = NumBookCluster-1; j > i; j-- ) {
+      p->cluster[j].a = p->cluster[j-1].a;
+      p->cluster[j].b = p->cluster[j-1].b;
+    }
+
+    p->cluster[i].a = HASH_KEY;
+    p->cluster[i].b
+      = ( (uint64_t)move<<22 ) | ( (uint64_t)ply << 41 )
+      | (uint64_t)( (root_turn<<21) | HAND_B );
+  }
+
+  return 0;
+}
+
+
+static int
+rep_check_learn( tree_t * restrict ptree, int ply )
+{
+  int n, i, imin;
+
+  n    = root_nrep + ply - 1;
+  imin = n - REP_MAX_PLY;
+  if ( imin < 0 ) { imin = 0; }
+
+  for ( i = n-2; i >= imin; i -= 2 )
+    if ( ptree->rep_board_list[i] == HASH_KEY
+        && ptree->rep_hand_list[i] == HAND_B ) { return four_fold_rep; }
+
+  return no_rep;
+}
+
+#endif /* no MINIMUM */
diff --git a/learn2.c b/learn2.c
new file mode 100644 (file)
index 0000000..109424f
--- /dev/null
+++ b/learn2.c
@@ -0,0 +1,856 @@
+#include <stdlib.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+#include <assert.h>
+#include "shogi.h"
+
+#if ! defined(MINIMUM)
+
+#define GO_THROUGH_ALL_PARAMETERS_BY_FOO                                  \
+  for ( i=0; i < nsquare*pos_n; i++ )           { Foo( pc_on_sq[0][i] ) } \
+  for ( i=0; i < nsquare*nsquare*kkp_end; i++ ) { Foo( kkp[0][0][i] ) }
+
+
+static void rmt( const double avalue[16], int pc );
+static void rparam( short *pv, float dv );
+static void fv_sym( void );
+static int brand( void );
+static int make_list( const tree_t * restrict ptree, int list0[52],
+                     int list1[52], int anpiece[16], param_t * restrict pd,
+                     float f );
+
+
+void
+ini_param( param_t *p )
+{
+  int i;
+
+  p->pawn       = p->lance      = p->knight     = p->silver     = 0.0;
+  p->gold       = p->bishop     = p->rook       = p->pro_pawn   = 0.0;
+  p->pro_lance  = p->pro_knight = p->pro_silver = p->horse      = 0.0;
+  p->dragon     = 0.0;
+
+#define Foo(x) p->x = 0;
+  GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+}
+
+
+void
+add_param( param_t *p1, const param_t *p2 )
+{
+  int i;
+
+  p1->pawn       += p2->pawn;
+  p1->lance      += p2->lance;
+  p1->knight     += p2->knight;
+  p1->silver     += p2->silver;
+  p1->gold       += p2->gold;
+  p1->bishop     += p2->bishop;
+  p1->rook       += p2->rook;
+  p1->pro_pawn   += p2->pro_pawn;
+  p1->pro_lance  += p2->pro_lance;
+  p1->pro_knight += p2->pro_knight;
+  p1->pro_silver += p2->pro_silver;
+  p1->horse      += p2->horse;
+  p1->dragon     += p2->dragon;
+
+#define Foo(x) p1->x += p2->x;
+  GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+}
+
+
+void
+fill_param_zero( void )
+{
+  int i;
+
+  p_value[15+pawn]       = 100;
+  p_value[15+lance]      = 300;
+  p_value[15+knight]     = 300;
+  p_value[15+silver]     = 400;
+  p_value[15+gold]       = 500;
+  p_value[15+bishop]     = 600;
+  p_value[15+rook]       = 700;
+  p_value[15+pro_pawn]   = 400;
+  p_value[15+pro_lance]  = 400;
+  p_value[15+pro_knight] = 400;
+  p_value[15+pro_silver] = 500;
+  p_value[15+horse]      = 800;
+  p_value[15+dragon]     = 1000;
+
+#define Foo(x) x = 0;
+  GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+
+  set_derivative_param();
+}
+
+
+void
+param_sym( param_t *p )
+{
+  int q, r, il, ir, ir0, jl, jr, k0l, k0r, k1l, k1r;
+
+  for ( k0l = 0; k0l < nsquare; k0l++ ) {
+    q = k0l / nfile;
+    r = k0l % nfile;
+    k0r = q*nfile + nfile-1-r;
+    if ( k0l > k0r ) { continue; }
+
+    for ( il = 0; il < fe_end; il++ ) {
+      if ( il < fe_hand_end ) { ir0 = il; }
+      else {
+       q = ( il- fe_hand_end ) / nfile;
+       r = ( il- fe_hand_end ) % nfile;
+       ir0 = q*nfile + nfile-1-r + fe_hand_end;
+      }
+
+      for ( jl = 0; jl <= il; jl++ ) {
+       if ( jl < fe_hand_end )
+         {
+           ir = ir0;
+           jr = jl;
+         }
+       else {
+         q = ( jl - fe_hand_end ) / nfile;
+         r = ( jl - fe_hand_end ) % nfile;
+         jr = q*nfile + nfile-1-r + fe_hand_end;
+         if ( jr > ir0 )
+           {
+             ir = jr;
+             jr = ir0;
+           }
+         else { ir = ir0; }
+       }
+       if ( k0l == k0r && il*(il+1)/2+jl >= ir*(ir+1)/2+jr ) { continue; }
+
+       p->PcPcOnSq(k0l,il,jl)
+         = p->PcPcOnSq(k0r,ir,jr)
+         = p->PcPcOnSq(k0l,il,jl) + p->PcPcOnSq(k0r,ir,jr);
+      }
+    }
+  }
+
+  for ( k0l = 0; k0l < nsquare; k0l++ ) {
+    q = k0l / nfile;
+    r = k0l % nfile;
+    k0r = q*nfile + nfile-1-r;
+    if ( k0l > k0r ) { continue; }
+
+    for ( k1l = 0; k1l < nsquare; k1l++ ) {
+      q = k1l / nfile;
+      r = k1l % nfile;
+      k1r = q*nfile + nfile-1-r;
+      if ( k0l == k0r && k1l > k1r ) { continue; }
+
+      for ( il = 0; il < kkp_end; il++ ) {
+       if ( il < kkp_hand_end ) { ir = il; }
+       else {
+         q  = ( il- kkp_hand_end ) / nfile;
+         r  = ( il- kkp_hand_end ) % nfile;
+         ir = q*nfile + nfile-1-r + kkp_hand_end;
+       }
+       if ( k0l == k0r && k1l == k1r && il >= ir ) { continue; }
+
+       p->kkp[k0l][k1l][il]
+         = p->kkp[k0r][k1r][ir]
+         = p->kkp[k0l][k1l][il] + p->kkp[k0r][k1r][ir];
+      }
+    }
+  }
+}
+
+
+static void fv_sym( void )
+{
+  int q, r, il, ir, ir0, jl, jr, k0l, k0r, k1l, k1r;
+
+  for ( k0l = 0; k0l < nsquare; k0l++ ) {
+    q = k0l / nfile;
+    r = k0l % nfile;
+    k0r = q*nfile + nfile-1-r;
+    if ( k0l > k0r ) { continue; }
+
+    for ( il = 0; il < fe_end; il++ ) {
+      if ( il < fe_hand_end ) { ir0 = il; }
+      else {
+       q = ( il- fe_hand_end ) / nfile;
+       r = ( il- fe_hand_end ) % nfile;
+       ir0 = q*nfile + nfile-1-r + fe_hand_end;
+      }
+
+      for ( jl = 0; jl <= il; jl++ ) {
+       if ( jl < fe_hand_end )
+         {
+           ir = ir0;
+           jr = jl;
+         }
+       else {
+         q = ( jl - fe_hand_end ) / nfile;
+         r = ( jl - fe_hand_end ) % nfile;
+         jr = q*nfile + nfile-1-r + fe_hand_end;
+         if ( jr > ir0 )
+           {
+             ir = jr;
+             jr = ir0;
+           }
+         else { ir = ir0; }
+       }
+       if ( k0l == k0r && il*(il+1)/2+jl >= ir*(ir+1)/2+jr ) { continue; }
+
+       PcPcOnSq(k0l,il,jl) = PcPcOnSq(k0r,ir,jr);
+      }
+    }
+  }
+
+  for ( k0l = 0; k0l < nsquare; k0l++ ) {
+    q = k0l / nfile;
+    r = k0l % nfile;
+    k0r = q*nfile + nfile-1-r;
+    if ( k0l > k0r ) { continue; }
+
+    for ( k1l = 0; k1l < nsquare; k1l++ ) {
+      q = k1l / nfile;
+      r = k1l % nfile;
+      k1r = q*nfile + nfile-1-r;
+      if ( k0l == k0r && k1l > k1r ) { continue; }
+
+      for ( il = 0; il < kkp_end; il++ ) {
+       if ( il < kkp_hand_end ) { ir = il; }
+       else {
+         q  = ( il- kkp_hand_end ) / nfile;
+         r  = ( il- kkp_hand_end ) % nfile;
+         ir = q*nfile + nfile-1-r + kkp_hand_end;
+       }
+       if ( k0l == k0r && k1l == k1r && il >= ir ) { continue; }
+
+       kkp[k0l][k1l][il] = kkp[k0r][k1r][ir];
+      }
+    }
+  }
+}
+
+
+double
+calc_penalty( void )
+{
+  uint64_t u64sum;
+  int i;
+
+  u64sum = 0;
+
+#define Foo(x) u64sum += (uint64_t)abs((int)x);
+  GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+
+  return (double)u64sum * FV_PENALTY;
+}
+
+
+void
+renovate_param( const param_t *pd )
+{
+  double *pv[14], *p;
+  double v[16];
+  unsigned int u32rand, u;
+  int i, j;
+
+  v[pawn]       = pd->pawn;         v[lance]      = pd->lance;
+  v[knight]     = pd->knight;       v[silver]     = pd->silver;
+  v[gold]       = pd->gold;         v[bishop]     = pd->bishop;
+  v[rook]       = pd->rook;         v[pro_pawn]   = pd->pro_pawn;
+  v[pro_lance]  = pd->pro_lance;    v[pro_knight] = pd->pro_knight;
+  v[pro_silver] = pd->pro_silver;   v[horse]      = pd->horse;
+  v[dragon]     = pd->dragon;       v[king]       = FLT_MAX;
+
+  pv[ 0] = v + pawn;         pv[ 1] = v + lance;
+  pv[ 2] = v + knight;       pv[ 3] = v + silver;
+  pv[ 4] = v + gold;         pv[ 5] = v + bishop;
+  pv[ 6] = v + rook;         pv[ 7] = v + pro_pawn;
+  pv[ 8] = v + pro_lance;    pv[ 9] = v + pro_knight;
+  pv[10] = v + pro_silver;   pv[11] = v + horse;
+  pv[12] = v + dragon;       pv[13] = v + king;
+
+  /* insertion sort */
+  for ( i = 13 - 2; i >= 0; i-- )
+    {
+      p = pv[i];
+      for ( j = i+1; *pv[j] < *p; j++ ) { pv[j-1] = pv[j]; }
+      pv[j-1] = p;
+    }
+
+  u32rand = rand32();
+  u       = u32rand % 7U;
+  u32rand = u32rand / 7U;
+  p = pv[u+6];  pv[u+6] = pv[12];  pv[12] = p;
+  for ( i = 5; i > 0; i-- )
+    {
+      u       = u32rand % (i+1);
+      u32rand = u32rand / (i+1);
+      p = pv[u];  pv[u] = pv[i];  pv[i] = p;
+
+      u       = u32rand % (i+1);
+      u32rand = u32rand / (i+1);
+      p = pv[u+6];  pv[u+6] = pv[i+6];  pv[i+6] = p;
+    }
+
+  *pv[ 0] = *pv[ 1] = -2.0;
+  *pv[ 2] = *pv[ 3] = *pv[ 4] = -1.0;
+  *pv[ 5] = *pv[ 6] = *pv[ 7] =  0.0;
+  *pv[ 8] = *pv[ 9] = *pv[10] =  1.0;
+  *pv[11] = *pv[12] =  2.0;
+
+  rmt( v, pawn );        rmt( v, lance );       rmt( v, knight );
+  rmt( v, silver );      rmt( v, gold );        rmt( v, bishop );
+  rmt( v, rook );        rmt( v, pro_pawn );    rmt( v, pro_lance );
+  rmt( v, pro_knight );  rmt( v, pro_silver );  rmt( v, horse );
+  rmt( v, dragon );
+
+#define Foo(v) rparam( &v, pd->v );
+  GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+
+  fv_sym();
+  set_derivative_param();
+  ehash_clear();
+}
+
+
+int
+out_param( void )
+{
+  size_t size;
+  FILE *pf;
+  int apc[17], apv[17];
+  int iret, i, j, pc, pv;
+
+  for ( i = 0; i < 17; i++ ) { apc[i] = i;  apv[i] = INT_MAX; }
+  apv[pawn]       = p_value_ex[15+pawn];
+  apv[lance]      = p_value_ex[15+lance];
+  apv[knight]     = p_value_ex[15+knight];
+  apv[silver]     = p_value_ex[15+silver];
+  apv[gold]       = p_value_ex[15+gold];
+  apv[bishop]     = p_value_ex[15+bishop];
+  apv[rook]       = p_value_ex[15+rook];
+  apv[pro_pawn]   = p_value_ex[15+pro_pawn];
+  apv[pro_lance]  = p_value_ex[15+pro_lance];
+  apv[pro_knight] = p_value_ex[15+pro_knight];
+  apv[pro_silver] = p_value_ex[15+pro_silver];
+  apv[horse]      = p_value_ex[15+horse];
+  apv[dragon]     = p_value_ex[15+dragon];
+
+  /* insertion sort */
+  for ( i = dragon-1; i >= 0; i-- )
+    {
+      pv = apv[i];  pc = apc[i];
+      for ( j = i+1; apv[j] < pv; j++ )
+       {
+         apv[j-1] = apv[j];
+         apc[j-1] = apc[j];
+       }
+      apv[j-1] = pv;  apc[j-1] = pc;
+    }
+      
+  pf = file_open( "param.h_", "w" );
+  if ( pf == NULL ) { return -2; }
+  
+  for ( i = 0; i < 13; i++ )
+    {
+      fprintf( pf, "#define " );
+      switch ( apc[i] )
+       {
+       case pawn:        fprintf( pf, "DPawn     " );  break;
+       case lance:       fprintf( pf, "DLance    " );  break;
+       case knight:      fprintf( pf, "DKnight   " );  break;
+       case silver:      fprintf( pf, "DSilver   " );  break;
+       case gold:        fprintf( pf, "DGold     " );  break;
+       case bishop:      fprintf( pf, "DBishop   " );  break;
+       case rook:        fprintf( pf, "DRook     " );  break;
+       case pro_pawn:    fprintf( pf, "DProPawn  " );  break;
+       case pro_lance:   fprintf( pf, "DProLance " );  break;
+       case pro_knight:  fprintf( pf, "DProKnight" );  break;
+       case pro_silver:  fprintf( pf, "DProSilver" );  break;
+       case horse:       fprintf( pf, "DHorse    " );  break;
+       case dragon:      fprintf( pf, "DDragon   " );  break;
+       }
+      fprintf( pf, "     %4d /* %4d */\n", p_value[15+apc[i]], apv[i] );
+    }
+  fprintf( pf, "#define DKing         15000\n\n" );
+
+  iret = file_close( pf );
+  if ( iret < 0 ) { return -2; }
+
+  pf = file_open( "fv.bin", "wb" );
+  if ( pf == NULL ) { return -2; }
+
+  size = nsquare * pos_n;
+  if ( fwrite( pc_on_sq, sizeof(short), size, pf ) != size )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+
+  size = nsquare * nsquare * kkp_end;
+  if ( fwrite( kkp, sizeof(short), size, pf ) != size )
+    {
+      str_error = str_io_error;
+      return -2;
+    }
+  
+  return file_close( pf );
+}
+
+
+void
+inc_param( const tree_t * restrict ptree, param_t * restrict pd, double dinc )
+{
+  float f;
+  int anpiece[16], list0[52], list1[52];
+  int nlist, sq_bk, sq_wk, k0, k1, l0, l1, i, j;
+
+  f     = (float)( dinc / (double)FV_SCALE );
+  nlist = make_list( ptree, list0, list1, anpiece, pd, f );
+  sq_bk = SQ_BKING;
+  sq_wk = Inv( SQ_WKING );
+
+  pd->pawn       += dinc * (double)anpiece[pawn];
+  pd->lance      += dinc * (double)anpiece[lance];
+  pd->knight     += dinc * (double)anpiece[knight];
+  pd->silver     += dinc * (double)anpiece[silver];
+  pd->gold       += dinc * (double)anpiece[gold];
+  pd->bishop     += dinc * (double)anpiece[bishop];
+  pd->rook       += dinc * (double)anpiece[rook];
+  pd->pro_pawn   += dinc * (double)anpiece[pro_pawn];
+  pd->pro_lance  += dinc * (double)anpiece[pro_lance];
+  pd->pro_knight += dinc * (double)anpiece[pro_knight];
+  pd->pro_silver += dinc * (double)anpiece[pro_silver];
+  pd->horse      += dinc * (double)anpiece[horse];
+  pd->dragon     += dinc * (double)anpiece[dragon];
+
+  for ( i = 0; i < nlist; i++ )
+    {
+      k0 = list0[i];
+      k1 = list1[i];
+      for ( j = 0; j <= i; j++ )
+       {
+         l0 = list0[j];
+         l1 = list1[j];
+         assert( k0 >= l0 && k1 >= l1 );
+         pd->PcPcOnSq( sq_bk, k0, l0 ) += f;
+         pd->PcPcOnSq( sq_wk, k1, l1 ) -= f;
+       }
+    }
+}
+
+
+static int
+make_list( const tree_t * restrict ptree, int list0[52], int list1[52],
+          int anpiece[16], param_t * restrict pd, float f )
+{
+  bitboard_t bb;
+  int list2[34];
+  int nlist, sq, sq_bk0, sq_bk1, sq_wk0, sq_wk1, n2, i, itemp1, itemp2;
+
+  itemp1          = (int)I2HandPawn(HAND_B);
+  itemp2          = (int)I2HandPawn(HAND_W);
+  anpiece[pawn]   = itemp1 - itemp2;
+
+  itemp1          = (int)I2HandLance(HAND_B);
+  itemp2          = (int)I2HandLance(HAND_W);
+  anpiece[lance]  = itemp1 - itemp2;
+
+  itemp1          = (int)I2HandKnight(HAND_B);
+  itemp2          = (int)I2HandKnight(HAND_W);
+  anpiece[knight] = itemp1 - itemp2;
+
+  itemp1          = (int)I2HandSilver(HAND_B);
+  itemp2          = (int)I2HandSilver(HAND_W);
+  anpiece[silver] = itemp1 - itemp2;
+
+  itemp1          = (int)I2HandGold(HAND_B);
+  itemp2          = (int)I2HandGold(HAND_W);
+  anpiece[gold]   = itemp1 - itemp2;
+
+  itemp1          = (int)I2HandBishop(HAND_B);
+  itemp2          = (int)I2HandBishop(HAND_W);
+  anpiece[bishop] = itemp1 - itemp2;
+
+  itemp1          = (int)I2HandRook(HAND_B);
+  itemp2          = (int)I2HandRook(HAND_W);
+  anpiece[rook]   = itemp1 - itemp2;
+
+  anpiece[pro_pawn]   = anpiece[pro_lance]  = anpiece[pro_knight] = 0;
+  anpiece[pro_silver] = anpiece[horse]      = anpiece[dragon]     = 0;
+  nlist  = 14;
+  sq_bk0 = SQ_BKING;
+  sq_wk0 = SQ_WKING;
+  sq_bk1 = Inv(SQ_WKING);
+  sq_wk1 = Inv(SQ_BKING);
+
+  list0[ 0] = f_hand_pawn   + I2HandPawn(HAND_B);
+  list0[ 1] = e_hand_pawn   + I2HandPawn(HAND_W);
+  list0[ 2] = f_hand_lance  + I2HandLance(HAND_B);
+  list0[ 3] = e_hand_lance  + I2HandLance(HAND_W);
+  list0[ 4] = f_hand_knight + I2HandKnight(HAND_B);
+  list0[ 5] = e_hand_knight + I2HandKnight(HAND_W);
+  list0[ 6] = f_hand_silver + I2HandSilver(HAND_B);
+  list0[ 7] = e_hand_silver + I2HandSilver(HAND_W);
+  list0[ 8] = f_hand_gold   + I2HandGold(HAND_B);
+  list0[ 9] = e_hand_gold   + I2HandGold(HAND_W);
+  list0[10] = f_hand_bishop + I2HandBishop(HAND_B);
+  list0[11] = e_hand_bishop + I2HandBishop(HAND_W);
+  list0[12] = f_hand_rook   + I2HandRook(HAND_B);
+  list0[13] = e_hand_rook   + I2HandRook(HAND_W);
+
+  list1[ 0] = f_hand_pawn   + I2HandPawn(HAND_W);
+  list1[ 1] = e_hand_pawn   + I2HandPawn(HAND_B);
+  list1[ 2] = f_hand_lance  + I2HandLance(HAND_W);
+  list1[ 3] = e_hand_lance  + I2HandLance(HAND_B);
+  list1[ 4] = f_hand_knight + I2HandKnight(HAND_W);
+  list1[ 5] = e_hand_knight + I2HandKnight(HAND_B);
+  list1[ 6] = f_hand_silver + I2HandSilver(HAND_W);
+  list1[ 7] = e_hand_silver + I2HandSilver(HAND_B);
+  list1[ 8] = f_hand_gold   + I2HandGold(HAND_W);
+  list1[ 9] = e_hand_gold   + I2HandGold(HAND_B);
+  list1[10] = f_hand_bishop + I2HandBishop(HAND_W);
+  list1[11] = e_hand_bishop + I2HandBishop(HAND_B);
+  list1[12] = f_hand_rook   + I2HandRook(HAND_W);
+  list1[13] = e_hand_rook   + I2HandRook(HAND_B);
+
+  pd->kkp[sq_bk0][sq_wk0][kkp_hand_pawn  +I2HandPawn(HAND_B)  ] += f;
+  pd->kkp[sq_bk0][sq_wk0][kkp_hand_lance +I2HandLance(HAND_B) ] += f;
+  pd->kkp[sq_bk0][sq_wk0][kkp_hand_knight+I2HandKnight(HAND_B)] += f;
+  pd->kkp[sq_bk0][sq_wk0][kkp_hand_silver+I2HandSilver(HAND_B)] += f;
+  pd->kkp[sq_bk0][sq_wk0][kkp_hand_gold  +I2HandGold(HAND_B)  ] += f;
+  pd->kkp[sq_bk0][sq_wk0][kkp_hand_bishop+I2HandBishop(HAND_B)] += f;
+  pd->kkp[sq_bk0][sq_wk0][kkp_hand_rook  +I2HandRook(HAND_B)  ] += f;
+
+  pd->kkp[sq_bk1][sq_wk1][kkp_hand_pawn  +I2HandPawn(HAND_W)  ] -= f;
+  pd->kkp[sq_bk1][sq_wk1][kkp_hand_lance +I2HandLance(HAND_W) ] -= f;
+  pd->kkp[sq_bk1][sq_wk1][kkp_hand_knight+I2HandKnight(HAND_W)] -= f;
+  pd->kkp[sq_bk1][sq_wk1][kkp_hand_silver+I2HandSilver(HAND_W)] -= f;
+  pd->kkp[sq_bk1][sq_wk1][kkp_hand_gold  +I2HandGold(HAND_W)  ] -= f;
+  pd->kkp[sq_bk1][sq_wk1][kkp_hand_bishop+I2HandBishop(HAND_W)] -= f;
+  pd->kkp[sq_bk1][sq_wk1][kkp_hand_rook  +I2HandRook(HAND_W)  ] -= f;
+
+  n2 = 0;
+  bb = BB_BPAWN;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_pawn+sq] += f;
+    anpiece[pawn] += 1;
+    list0[nlist] = f_pawn + sq;
+    list2[n2]    = e_pawn + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WPAWN;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_pawn+Inv(sq)] -= f;
+    anpiece[pawn] -= 1;
+    list0[nlist] = e_pawn + sq;
+    list2[n2]    = f_pawn + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+  n2 = 0;
+  bb = BB_BLANCE;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_lance+sq] += f;
+    anpiece[lance] += 1;
+    list0[nlist] = f_lance + sq;
+    list2[n2]    = e_lance + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WLANCE;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_lance+Inv(sq)] -= f;
+    anpiece[lance] -= 1;
+    list0[nlist] = e_lance + sq;
+    list2[n2]    = f_lance + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BKNIGHT;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_knight+sq] += f;
+    anpiece[knight] += 1;
+    list0[nlist] = f_knight + sq;
+    list2[n2]    = e_knight + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WKNIGHT;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_knight+Inv(sq)] -= f;
+    anpiece[knight] -= 1;
+    list0[nlist] = e_knight + sq;
+    list2[n2]    = f_knight + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BSILVER;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_silver+sq] += f;
+    anpiece[silver] += 1;
+    list0[nlist] = f_silver + sq;
+    list2[n2]    = e_silver + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WSILVER;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_silver+Inv(sq)] -= f;
+    anpiece[silver] -= 1;
+    list0[nlist] = e_silver + sq;
+    list2[n2]    = f_silver + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BTGOLD;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_gold+sq] += f;
+    anpiece[BOARD[sq]] += 1;
+    list0[nlist] = f_gold + sq;
+    list2[n2]    = e_gold + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WTGOLD;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_gold+Inv(sq)] -= f;
+    anpiece[-BOARD[sq]] -= 1;
+    list0[nlist] = e_gold + sq;
+    list2[n2]    = f_gold + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BBISHOP;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_bishop+sq] += f;
+    anpiece[bishop] += 1;
+    list0[nlist] = f_bishop + sq;
+    list2[n2]    = e_bishop + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WBISHOP;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_bishop+Inv(sq)] -= f;
+    anpiece[bishop] -= 1;
+    list0[nlist] = e_bishop + sq;
+    list2[n2]    = f_bishop + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BHORSE;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_horse+sq] += f;
+    anpiece[horse] += 1;
+    list0[nlist] = f_horse + sq;
+    list2[n2]    = e_horse + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WHORSE;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_horse+Inv(sq)] -= f;
+    anpiece[horse] -= 1;
+    list0[nlist] = e_horse + sq;
+    list2[n2]    = f_horse + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BROOK;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_rook+sq] += f;
+    anpiece[rook] += 1;
+    list0[nlist] = f_rook + sq;
+    list2[n2]    = e_rook + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WROOK;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_rook+Inv(sq)] -= f;
+    anpiece[rook] -= 1;
+    list0[nlist] = e_rook + sq;
+    list2[n2]    = f_rook + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+  n2 = 0;
+  bb = BB_BDRAGON;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk0][sq_wk0][kkp_dragon+sq] += f;
+    anpiece[dragon] += 1;
+    list0[nlist] = f_dragon + sq;
+    list2[n2]    = e_dragon + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+
+  bb = BB_WDRAGON;
+  while ( BBToU(bb) ) {
+    sq = FirstOne( bb );
+    Xor( sq, bb );
+
+    pd->kkp[sq_bk1][sq_wk1][kkp_dragon+Inv(sq)] -= f;
+    anpiece[dragon] -= 1;
+    list0[nlist] = e_dragon + sq;
+    list2[n2]    = f_dragon + Inv(sq);
+    nlist += 1;
+    n2    += 1;
+  }
+  for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+  assert( nlist <= 52 );
+  return nlist;
+}
+
+
+static void
+rmt( const double avalue[16], int pc )
+{
+  int pc_v;
+
+  pc_v  = (int)p_value[15+pc] + (int)avalue[pc];
+
+  if ( 0 < pc_v && pc_v <= SHRT_MAX ) { p_value[15+pc] = (short)pc_v; }
+  else {
+    out_warning( "A material value is out of bounce. (%s=%d)\n",
+                astr_table_piece[pc], pc_v );
+  }
+}
+
+
+static void
+rparam( short *pv, float dv )
+{
+  int v, istep;
+
+  istep  = brand();
+  istep += brand();
+  v      = *pv;
+
+  if      ( v > 0 ) { dv -= (float)FV_PENALTY; }
+  else if ( v < 0 ) { dv += (float)FV_PENALTY; }
+
+  if      ( dv >= 0.0 && v <= SHRT_MAX - istep ) { v += istep; }
+  else if ( dv <= 0.0 && v >= SHRT_MIN + istep ) { v -= istep; }
+  else { out_warning( "A fvcoef parameter is out of bounce.\n" ); }
+
+  *pv = (short)v;
+}
+
+
+static int
+brand( void )
+{
+  static unsigned int urand = 0;
+  static unsigned int uc    = 31;
+  unsigned int uret;
+
+  if ( uc == 31 )
+    {
+      urand = rand32();
+      uc    = 0;
+    }
+  else { uc += 1; }
+  uret    = urand & 1U;
+  urand >>= 1;
+  return uret;
+}
+
+#endif /* MINIMUM */
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..f84ad15
--- /dev/null
+++ b/main.c
@@ -0,0 +1,154 @@
+/*
+  BUG LIST                                                       
+
+  - detection of repetitions can be wrong due to collision of hash keys and
+    limitation of history table size.
+
+  - detection of mates fails if all of pseudo-legal evasions are perpetual
+    checks.  Father more, inferior evasions, such as unpromotion of
+    bishop, rook, and lance at 8th rank, are not counted for the mate
+    detection. 
+
+  - detection of perpetual checks fails if one of those inferior
+    evasions makes a position that occurred four times.
+*/
+/*
+  TODO:
+  - idirec && is_pinned_on_black_king();
+  - aifile and airank
+  - incheck at quies
+  - max legal moves
+  - tactical macro
+  - out_warning( "A node returns a value lower than mate." ); is obsolate.
+  - do_mate in hash
+  - pv store to hash
+  - no threat
+  - use IsDiscover macro
+  - change hash_store_pv()
+  - dek.c is obsolate.
+  - limit time ? ? num
+  - hash.bin
+  - SHARE to all transition table
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_WIN32)
+#  include <fcntl.h>
+#endif
+#include "shogi.h"
+
+static int main_child( tree_t * restrict ptree );
+
+int CONV_CDECL
+#if defined(CSASHOGI)
+main( int argc, char *argv[] )
+#else
+main()
+#endif
+{
+  int iret;
+  tree_t * restrict ptree;
+
+#if defined(TLP)
+  ptree = tlp_atree_work;
+#else
+  ptree = &tree;
+#endif
+
+#if defined(CSASHOGI) && defined(_WIN32)
+  FreeConsole();
+  if ( argc != 2 || strcmp( argv[1], "csa_shogi" ) )
+    {
+      MessageBox( NULL,
+                 "The executable image is not intended\x0d"
+                 "as an independent program file.\x0d"
+                 "Execute CSA.EXE instead.",
+                 str_myname, MB_OK | MB_ICONINFORMATION );
+      return EXIT_FAILURE;
+    }
+#endif
+
+  if ( ini( ptree ) < 0 )
+    {
+      out_error( "%s", str_error );
+      return EXIT_SUCCESS;
+    }
+
+  for ( ;; )
+    {
+      iret = main_child( ptree );
+      if ( iret == -1 )
+       {
+         out_error( "%s", str_error );
+         ShutdownClient;
+         break;
+       }
+      else if ( iret == -2 )
+       {
+         out_warning( "%s", str_error );
+         ShutdownClient;
+         continue;
+       }
+      else if ( iret == -3 ) { break; }
+    }
+
+  if ( fin() < 0 ) { out_error( "%s", str_error ); }
+
+  return EXIT_SUCCESS;
+}
+
+
+static int
+main_child( tree_t * restrict ptree )
+{
+  int iret;
+
+#if defined(DEKUNOBOU)
+  if ( dek_ngame && ( game_status & mask_game_end ) )
+    {
+      TlpEnd();
+      if ( dek_next_game( ptree ) < 0 )
+       {
+         out_error( "%s", str_error );
+         return -3;
+       }
+    }
+#endif
+
+  /* ponder a move */
+  ponder_move = 0;
+  iret = ponder( ptree );
+  if ( iret < 0 ) { return iret; }
+  else if ( game_status & flag_quit ) { return -3; }
+
+  /* move prediction succeeded, pondering finished,
+     and computer made a move. */
+  else if ( iret == 2 ) { return 1; }
+
+  /* move prediction failed, pondering aborted,
+     and we have opponent's move in input buffer. */
+  else if ( ponder_move == MOVE_PONDER_FAILED )
+    {
+    }
+
+  /* pondering is interrupted or ended.
+     do nothing until we get next input line. */
+  else {
+    TlpEnd();
+    show_prompt();
+  }
+
+  
+  iret = next_cmdline( 1 );
+  if ( iret < 0 ) { return iret; }
+  else if ( game_status & flag_quit ) { return -3; }
+
+
+  iret = procedure( ptree );
+  if ( iret < 0 ) { return iret; }
+  else if ( game_status & flag_quit ) { return -3; }
+
+  return 1;
+}
diff --git a/makemove.c b/makemove.c
new file mode 100644 (file)
index 0000000..83d8c9e
--- /dev/null
@@ -0,0 +1,508 @@
+#include <assert.h>
+#include <string.h>
+#include "shogi.h"
+
+#define DropB( PIECE, piece )  Xor( to, BB_B ## PIECE );                    \
+                               HASH_KEY    ^= ( b_ ## piece ## _rand )[to]; \
+                               HAND_B      -= flag_hand_ ## piece;          \
+                               BOARD[to]  = piece
+
+#define DropW( PIECE, piece )  Xor( to, BB_W ## PIECE );                    \
+                               HASH_KEY    ^= ( w_ ## piece ## _rand )[to]; \
+                               HAND_W      -= flag_hand_ ## piece;          \
+                               BOARD[to]  = - piece
+
+#define CapB( PIECE, piece, pro_piece )                   \
+          Xor( to, BB_B ## PIECE );                       \
+          HASH_KEY  ^= ( b_ ## pro_piece ## _rand )[to];  \
+          HAND_W    += flag_hand_ ## piece;               \
+          MATERIAL  -= MT_CAP_ ## PIECE
+
+#define CapW( PIECE, piece, pro_piece )                   \
+          Xor( to, BB_W ## PIECE );                       \
+          HASH_KEY  ^= ( w_ ## pro_piece ## _rand )[to];  \
+          HAND_B    += flag_hand_ ## piece;               \
+          MATERIAL  += MT_CAP_ ## PIECE
+
+#define NocapProB( PIECE, PRO_PIECE, piece, pro_piece )       \
+          Xor( from, BB_B ## PIECE );                         \
+          Xor( to,   BB_B ## PRO_PIECE );                     \
+          HASH_KEY    ^= ( b_ ## pro_piece ## _rand )[to]     \
+                       ^ ( b_ ## piece     ## _rand )[from];  \
+          MATERIAL    += MT_PRO_ ## PIECE;                    \
+          BOARD[to] = pro_piece
+
+#define NocapProW( PIECE, PRO_PIECE, piece, pro_piece )       \
+          Xor( from, BB_W ## PIECE );                         \
+          Xor( to,   BB_W ## PRO_PIECE );                     \
+          HASH_KEY    ^= ( w_ ## pro_piece ## _rand )[to]     \
+                       ^ ( w_ ## piece     ## _rand )[from];  \
+          MATERIAL    -= MT_PRO_ ## PIECE;                    \
+          BOARD[to]  = - pro_piece
+#define NocapNoproB( PIECE, piece )                          \
+          SetClear( BB_B ## PIECE );                         \
+          HASH_KEY    ^= ( b_ ## piece ## _rand )[to]        \
+                       ^ ( b_ ## piece ## _rand )[from];     \
+          BOARD[to] = piece
+
+#define NocapNoproW( PIECE, piece )                          \
+          SetClear( BB_W ## PIECE );                         \
+          HASH_KEY    ^= ( w_ ## piece ## _rand )[to]        \
+                       ^ ( w_ ## piece ## _rand )[from];     \
+          BOARD[to] = - piece
+
+
+void
+make_move_b( tree_t * restrict ptree, unsigned int move, int ply )
+{
+  const int from = (int)I2From(move);
+  const int to   = (int)I2To(move);
+  const int nrep  = root_nrep + ply - 1;
+
+  assert( UToCap(move) != king );
+  assert( move );
+  assert( is_move_valid( ptree, move, black ) );
+
+  ptree->rep_board_list[nrep]    = HASH_KEY;
+  ptree->rep_hand_list[nrep]     = HAND_B;
+  ptree->save_material[ply]      = (short)MATERIAL;
+  ptree->stand_pat[ply+1]        = score_bound;
+
+  if ( from >= nsquare )
+    {
+      switch ( From2Drop(from) )
+       {
+       case pawn:   Xor( to-nfile, BB_BPAWN_ATK );
+                     DropB( PAWN,   pawn   );  break;
+       case lance:  DropB( LANCE,  lance  );  break;
+       case knight: DropB( KNIGHT, knight );  break;
+       case silver: DropB( SILVER, silver );  break;
+       case gold:   DropB( GOLD,   gold   );
+                     Xor( to, BB_BTGOLD );     break;
+       case bishop: DropB( BISHOP, bishop );
+                     Xor( to, BB_B_BH );       break;
+       default:     assert( From2Drop(from) == rook );
+                     DropB( ROOK,  rook );
+                    Xor( to, BB_B_RD );       break;
+       }
+      Xor( to, BB_BOCCUPY );
+      XorFile( to, OCCUPIED_FILE );
+      XorDiag2( to, OCCUPIED_DIAG2 );
+      XorDiag1( to, OCCUPIED_DIAG1 );
+    }
+  else {
+    const int ipiece_move = (int)I2PieceMove(move);
+    const int ipiece_cap  = (int)UToCap(move);
+    const int is_promote  = (int)I2IsPromote(move);
+    bitboard_t bb_set_clear;
+
+    BBOr( bb_set_clear, abb_mask[from], abb_mask[to] );
+    SetClear( BB_BOCCUPY );
+    BOARD[from] = empty;
+
+    if ( is_promote ) switch( ipiece_move )
+      {
+      case pawn:   Xor( to, BB_BPAWN_ATK );
+                   Xor( to, BB_BTGOLD );
+                   NocapProB( PAWN,   PRO_PAWN,   pawn,   pro_pawn );   break;
+      case lance:  Xor( to, BB_BTGOLD );
+                   NocapProB( LANCE,  PRO_LANCE,  lance,  pro_lance );  break;
+      case knight: Xor( to, BB_BTGOLD );
+                   NocapProB( KNIGHT, PRO_KNIGHT, knight, pro_knight ); break;
+      case silver: Xor( to, BB_BTGOLD );
+                   NocapProB( SILVER, PRO_SILVER, silver, pro_silver ); break;
+      case bishop: Xor( to, BB_B_HDK );
+                  SetClear( BB_B_BH );
+                   NocapProB( BISHOP, HORSE,      bishop, horse );      break;
+      default:     assert( ipiece_move == rook );
+                   Xor( to, BB_B_HDK );
+                  SetClear( BB_B_RD );
+                   NocapProB( ROOK,   DRAGON,     rook,   dragon );     break;
+      }
+    else switch ( ipiece_move )
+      {
+      case pawn:       Xor( to-nfile, BB_BPAWN_ATK );
+                       Xor( to,       BB_BPAWN_ATK );
+                       NocapNoproB( PAWN,   pawn);       break;
+      case lance:      NocapNoproB( LANCE,  lance);      break;
+      case knight:     NocapNoproB( KNIGHT, knight);     break;
+      case silver:     NocapNoproB( SILVER, silver);     break;
+      case gold:       NocapNoproB( GOLD,   gold);
+                       SetClear( BB_BTGOLD );             break;
+      case bishop:     SetClear( BB_B_BH );
+                       NocapNoproB( BISHOP, bishop);     break;
+      case rook:       NocapNoproB( ROOK,   rook);
+                       SetClear( BB_B_RD );                break;
+      case king:       HASH_KEY ^= b_king_rand[to] ^ b_king_rand[from];
+                       SetClear( BB_B_HDK );
+                       BOARD[to] = king;
+                       SQ_BKING  = (char)to;           break;
+      case pro_pawn:   NocapNoproB( PRO_PAWN, pro_pawn );
+                       SetClear( BB_BTGOLD );             break;
+      case pro_lance:  NocapNoproB( PRO_LANCE, pro_lance );
+                       SetClear( BB_BTGOLD );             break;
+      case pro_knight: NocapNoproB( PRO_KNIGHT, pro_knight );
+                       SetClear( BB_BTGOLD );             break;
+      case pro_silver: NocapNoproB( PRO_SILVER, pro_silver );
+                       SetClear( BB_BTGOLD );             break;
+      case horse:      NocapNoproB( HORSE, horse );
+                       SetClear( BB_B_HDK );
+                       SetClear( BB_B_BH );                break;
+      default:         assert( ipiece_move == dragon );
+                       NocapNoproB( DRAGON, dragon );
+                       SetClear( BB_B_HDK );
+                       SetClear( BB_B_RD );                break;
+      }
+    
+    if ( ipiece_cap )
+      {
+       switch( ipiece_cap )
+         {
+         case pawn:       CapW( PAWN, pawn, pawn );
+                           Xor( to+nfile, BB_WPAWN_ATK );               break;
+         case lance:      CapW( LANCE,  lance, lance );       break;
+         case knight:     CapW( KNIGHT, knight, knight );      break;
+         case silver:     CapW( SILVER, silver, silver );      break;
+         case gold:       CapW( GOLD,   gold,   gold );
+                           Xor( to, BB_WTGOLD );                       break;
+         case bishop:     CapW( BISHOP, bishop, bishop );
+                           Xor( to, BB_W_BH );                          break;
+         case rook:       CapW( ROOK, rook, rook);
+                           Xor( to, BB_W_RD );                          break;
+         case pro_pawn:   CapW( PRO_PAWN, pawn, pro_pawn );
+                           Xor( to, BB_WTGOLD );                       break;
+         case pro_lance:  CapW( PRO_LANCE, lance, pro_lance );
+                           Xor( to, BB_WTGOLD );                       break;
+         case pro_knight: CapW( PRO_KNIGHT, knight, pro_knight );
+                           Xor( to, BB_WTGOLD );                       break;
+         case pro_silver: CapW( PRO_SILVER, silver, pro_silver );
+                           Xor( to, BB_WTGOLD );                       break;
+         case horse:      CapW( HORSE, bishop, horse );
+                           Xor( to, BB_W_HDK );
+                          Xor( to, BB_W_BH );                          break;
+         default:         assert( ipiece_cap == dragon );
+                           CapW( DRAGON, rook, dragon );
+                           Xor( to, BB_W_HDK );
+                          Xor( to, BB_W_RD );                         break;
+         }
+       Xor( to, BB_WOCCUPY );
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+      }
+    else {
+      SetClearFile( from, to, OCCUPIED_FILE );
+      SetClearDiag1( from, to, OCCUPIED_DIAG1 );
+      SetClearDiag2( from, to, OCCUPIED_DIAG2 );
+    }
+  }
+
+  assert( exam_bb( ptree ) );
+}
+
+
+void
+make_move_w( tree_t * restrict ptree, unsigned int move, int ply )
+{
+  const int from = (int)I2From(move);
+  const int to   = (int)I2To(move);
+  const int nrep  = root_nrep + ply - 1;
+
+  assert( UToCap(move) != king );
+  assert( move );
+  assert( is_move_valid( ptree, move, white ) );
+
+  ptree->rep_board_list[nrep]    = HASH_KEY;
+  ptree->rep_hand_list[nrep]     = HAND_B;
+  ptree->save_material[ply]      = (short)MATERIAL;
+  ptree->stand_pat[ply+1]        = score_bound;
+
+  if ( from >= nsquare )
+    {
+      switch( From2Drop(from) )
+       {
+       case pawn:   Xor( to+nfile, BB_WPAWN_ATK );
+                     DropW( PAWN,   pawn );    break;
+       case lance:  DropW( LANCE,  lance );   break;
+       case knight: DropW( KNIGHT, knight );  break;
+       case silver: DropW( SILVER, silver );  break;
+       case gold:   DropW( GOLD,   gold );
+                     Xor( to, BB_WTGOLD );     break;
+       case bishop: DropW( BISHOP, bishop );
+                     Xor( to, BB_W_BH );       break;
+       default:     DropW( ROOK,   rook );
+                     Xor( to, BB_W_RD );       break;
+       }
+      Xor( to, BB_WOCCUPY );
+      XorFile( to, OCCUPIED_FILE );
+      XorDiag2( to, OCCUPIED_DIAG2 );
+      XorDiag1( to, OCCUPIED_DIAG1 );
+    }
+  else {
+    const int ipiece_move = (int)I2PieceMove(move);
+    const int ipiece_cap  = (int)UToCap(move);
+    const int is_promote  = (int)I2IsPromote(move);
+    bitboard_t bb_set_clear;
+
+    BBOr( bb_set_clear, abb_mask[from], abb_mask[to] );
+    SetClear( BB_WOCCUPY );
+    BOARD[from] = empty;
+
+    if ( is_promote) switch( ipiece_move )
+      {
+      case pawn:   NocapProW( PAWN, PRO_PAWN, pawn, pro_pawn );
+                   Xor( to, BB_WPAWN_ATK );
+                   Xor( to, BB_WTGOLD );                           break;
+      case lance:  NocapProW( LANCE, PRO_LANCE, lance, pro_lance );
+                   Xor( to, BB_WTGOLD );                           break;
+      case knight: NocapProW( KNIGHT, PRO_KNIGHT, knight, pro_knight );
+                   Xor( to, BB_WTGOLD );                           break;
+      case silver: NocapProW( SILVER, PRO_SILVER, silver, pro_silver );
+                   Xor( to, BB_WTGOLD );                           break;
+      case bishop: NocapProW( BISHOP, HORSE, bishop, horse );
+                   Xor( to, BB_W_HDK );
+                  SetClear( BB_W_BH );                              break;
+      default:     NocapProW( ROOK, DRAGON, rook, dragon);
+                   Xor( to, BB_W_HDK );
+                  SetClear( BB_W_RD );                              break;
+      }
+    else switch ( ipiece_move )
+      {
+      case pawn:       NocapNoproW( PAWN, pawn );
+                       Xor( to+nfile, BB_WPAWN_ATK );
+                       Xor( to,       BB_WPAWN_ATK );     break;
+      case lance:      NocapNoproW( LANCE,     lance);      break;
+      case knight:     NocapNoproW( KNIGHT,    knight);     break;
+      case silver:     NocapNoproW( SILVER,    silver);     break;
+      case gold:       NocapNoproW( GOLD,      gold);
+                       SetClear( BB_WTGOLD );             break;
+      case bishop:     NocapNoproW( BISHOP,    bishop);
+                       SetClear( BB_W_BH );                break;
+      case rook:       NocapNoproW( ROOK,      rook);
+                       SetClear( BB_W_RD );                break;
+      case king:       HASH_KEY    ^= w_king_rand[to] ^ w_king_rand[from];
+                       BOARD[to]  = - king;
+                       SQ_WKING   = (char)to;
+                       SetClear( BB_W_HDK );               break;
+      case pro_pawn:   NocapNoproW( PRO_PAWN,   pro_pawn);
+                       SetClear( BB_WTGOLD );             break;
+      case pro_lance:  NocapNoproW( PRO_LANCE,  pro_lance);
+                       SetClear( BB_WTGOLD );             break;
+      case pro_knight: NocapNoproW( PRO_KNIGHT, pro_knight);
+                       SetClear( BB_WTGOLD );             break;
+      case pro_silver: NocapNoproW( PRO_SILVER, pro_silver);
+                       SetClear( BB_WTGOLD );             break;
+      case horse:      NocapNoproW( HORSE, horse );
+                       SetClear( BB_W_HDK );
+                       SetClear( BB_W_BH );                break;
+      default:         NocapNoproW( DRAGON, dragon );
+                       SetClear( BB_W_HDK );
+                       SetClear( BB_W_RD );                break;
+      }
+
+    if ( ipiece_cap )
+      {
+       switch( ipiece_cap )
+         {
+         case pawn:       CapB( PAWN, pawn, pawn );
+                           Xor( to-nfile, BB_BPAWN_ATK );           break;
+         case lance:      CapB( LANCE,  lance,  lance );           break;
+         case knight:     CapB( KNIGHT, knight, knight );          break;
+         case silver:     CapB( SILVER, silver, silver );          break;
+         case gold:       CapB( GOLD,   gold,   gold );
+                           Xor( to, BB_BTGOLD );                   break;
+         case bishop:     CapB( BISHOP, bishop, bishop );
+                           Xor( to, BB_B_BH );                      break;
+         case rook:       CapB( ROOK, rook, rook );
+                           Xor( to, BB_B_RD );                      break;
+         case pro_pawn:   CapB( PRO_PAWN, pawn, pro_pawn );
+                           Xor( to, BB_BTGOLD );                   break;
+         case pro_lance:  CapB( PRO_LANCE, lance, pro_lance );
+                           Xor( to, BB_BTGOLD );                   break;
+         case pro_knight: CapB( PRO_KNIGHT, knight, pro_knight );
+                           Xor( to, BB_BTGOLD );                   break;
+         case pro_silver: CapB( PRO_SILVER, silver, pro_silver );
+                           Xor( to, BB_BTGOLD );                   break;
+         case horse:      CapB( HORSE, bishop, horse );
+                           Xor( to, BB_B_HDK );
+                           Xor( to, BB_B_BH );                      break;
+         default:         CapB( DRAGON, rook, dragon );
+                           Xor( to, BB_B_HDK );
+                           Xor( to, BB_B_RD );                      break;
+         }
+       Xor( to, BB_BOCCUPY );
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+      }
+    else {
+      SetClearFile( from, to, OCCUPIED_FILE );
+      SetClearDiag1( from, to, OCCUPIED_DIAG1 );
+      SetClearDiag2( from, to, OCCUPIED_DIAG2 );
+    }
+  }
+
+  assert( exam_bb( ptree ) );
+}
+
+#undef DropB
+#undef DropW
+#undef CapB
+#undef CapW
+#undef NocapProB
+#undef NocapProW
+#undef NocapNoproB
+#undef NocapNoproW
+
+/*
+ * flag_detect_hang
+ * flag_rep
+ * flag_time
+ * flag_nomake_move
+ * flag_history
+ * flag_rejections
+ */
+int
+make_move_root( tree_t * restrict ptree, unsigned int move, int flag )
+{
+  int check, drawn, iret, i, n;
+
+  ptree->save_material[0] = (short)MATERIAL;
+  MakeMove( root_turn, move, 1 );
+
+  /* detect hang-king */
+  if ( ( flag & flag_detect_hang ) && InCheck(root_turn) )
+    {
+      str_error = str_king_hang;
+      UnMakeMove( root_turn, move, 1 );
+      return -2;
+    }
+
+  drawn = 0;
+  check = InCheck( Flip(root_turn) );
+  ptree->move_last[1]  = ptree->move_last[0];
+  if ( check )
+    {
+      ptree->nsuc_check[2] = (unsigned char)( ptree->nsuc_check[0] + 1U );
+    }
+  else { ptree->nsuc_check[2] = 0; }
+
+  /* detect repetitions */
+  if ( flag & flag_rep )
+    {
+      switch ( detect_repetition( ptree, 2, Flip(root_turn), 3 ) )
+       {
+       case perpetual_check:
+         str_error = str_perpet_check;
+         UnMakeMove( root_turn, move, 1 );
+         return -2;
+      
+       case four_fold_rep:
+         drawn = 1;
+         break;
+       }
+    }
+
+  /* return, since all of rule-checks were done */
+  if ( flag & flag_nomake_move )
+    {
+      UnMakeMove( root_turn, move, 1 );
+      return drawn ? 2 : 1;
+    }
+
+  if ( drawn ) { game_status |= flag_drawn; }
+
+  /* renovate time */
+  if ( flag & flag_time )
+    {
+      iret = renovate_time( root_turn );
+      if ( iret < 0 ) { return iret; }
+    }
+
+  root_turn = Flip( root_turn );
+
+  /* detect checkmate */
+  if ( check && is_mate( ptree, 1 ) ) { game_status |= flag_mated; }
+
+  /* save history */
+  if ( flag & flag_history )
+    {
+      /* save history for book learning */
+      if ( record_game.moves < HASH_REG_HIST_LEN )
+       {
+         history_book_learn[ record_game.moves ].move_played = move;
+         history_book_learn[ record_game.moves ].hand_played
+           = ptree->rep_hand_list[ root_nrep ];
+         history_book_learn[ record_game.moves ].key_played
+           = (unsigned int)ptree->rep_board_list[ root_nrep ];
+       }
+
+      out_CSA( ptree, &record_game, move );
+    }
+
+  /* add rejections */
+  if ( flag & flag_rejections ) { add_rejections_root( ptree, move ); }
+
+  /* renew repetition table */
+  n = root_nrep;
+  if ( n >= REP_HIST_LEN - PLY_MAX -1 )
+    {
+      for ( i = 0; i < n; i++ )
+       {
+         ptree->rep_board_list[i] = ptree->rep_board_list[i+1];
+         ptree->rep_hand_list[i]  = ptree->rep_hand_list[i+1];
+       }
+    }
+  else { root_nrep++; }
+
+  ptree->nsuc_check[PLY_MAX] = ptree->nsuc_check[0];
+  ptree->nsuc_check[0]       = ptree->nsuc_check[1];
+  ptree->nsuc_check[1]       = ptree->nsuc_check[2];
+
+  /* renovate pv */
+  last_root_value_save = last_root_value;
+  last_pv_save         = last_pv;
+  if ( last_pv.a[1] == move && last_pv.length >= 2 )
+    {
+      if ( last_pv.depth )
+       {
+#if PLY_INC == EXT_CHECK
+         if ( ! check )
+#endif
+           last_pv.depth--;
+       }
+      last_pv.length--;
+      memmove( &(last_pv.a[1]), &(last_pv.a[2]),
+              last_pv.length * sizeof( unsigned int ) );
+    }
+  else {
+    last_pv.a[0]    = 0;
+    last_pv.a[1]    = 0;
+    last_pv.depth   = 0;
+    last_pv.length  = 0;
+    last_root_value = 0;
+  }
+
+  return 1;
+}
+
+
+void
+unmake_move_root( tree_t * restrict ptree, unsigned int move )
+{
+  last_root_value = last_root_value_save;
+  last_pv         = last_pv_save;
+
+  ptree->nsuc_check[1] = ptree->nsuc_check[0];
+  ptree->nsuc_check[0] = ptree->nsuc_check[PLY_MAX];
+  
+  root_nrep   -= 1;
+  game_status &= ~( flag_drawn | flag_mated );
+  root_turn   = Flip(root_turn);
+
+  ptree->save_material[1]      = ptree->save_material[0];
+  UnMakeMove( root_turn, move, 1 );
+
+  sub_rejections_root( ptree, move );
+}
diff --git a/mate1ply.c b/mate1ply.c
new file mode 100644 (file)
index 0000000..b09a6d1
--- /dev/null
@@ -0,0 +1,2155 @@
+#include <assert.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+#define DebugOut { static int count = 0; \
+                   if ( count++ < 16 ) { out_CSA_posi( ptree, stdout, 0 ); } }
+
+static int can_w_king_escape( tree_t * restrict ptree, int to, bitboard_t bb );
+static int can_b_king_escape( tree_t * restrict ptree, int to, bitboard_t bb );
+static int can_w_piece_capture( const tree_t * restrict ptree, int to );
+static int can_b_piece_capture( const tree_t * restrict ptree, int to );
+
+
+unsigned int
+is_b_mate_in_1ply( tree_t * restrict ptree )
+{
+  bitboard_t bb, bb_temp, bb_check, bb_check_pro, bb_attacks, bb_drop, bb_move;
+  unsigned int ubb;
+  int to, from, idirec;
+
+  assert( ! is_black_attacked( ptree, SQ_BKING ) );
+
+  /*  Drops  */
+  BBOr( bb_drop, BB_BOCCUPY, BB_WOCCUPY );
+  BBNot( bb_drop, bb_drop );
+
+  if ( IsHandRook(HAND_B) ) {
+
+    BBAnd( bb, abb_w_gold_attacks[SQ_WKING],
+          abb_b_gold_attacks[SQ_WKING] );
+    BBAnd( bb, bb, bb_drop );
+    while( BBToU(bb) )
+      {
+       to = FirstOne( bb );
+       Xor( to, bb );
+
+       if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+       bb_attacks                     = abb_file_attacks[to][0];
+       bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+       if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_w_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(rook);
+      }
+
+  } else if ( IsHandLance(HAND_B) && SQ_WKING <= I2 ) {
+
+    to = SQ_WKING+nfile;
+    if ( ! BOARD[to] && is_white_attacked( ptree, to ) )
+      {
+       bb_attacks = abb_file_attacks[to][0];
+       if ( ! can_w_king_escape( ptree, to, bb_attacks )
+            && ! can_w_piece_capture( ptree, to ) )
+         {
+           return To2Move(to) | Drop2Move(lance);
+         }
+      }
+  }
+
+  if ( IsHandBishop(HAND_B) ) {
+
+    BBAnd( bb, abb_w_silver_attacks[SQ_WKING],
+          abb_b_silver_attacks[SQ_WKING] );
+    BBAnd( bb, bb, bb_drop );
+    while( BBToU(bb) )
+      {
+       to = FirstOne( bb );
+       Xor( to, bb );
+
+       if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+       BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+             abb_bishop_attacks_rl45[to][0] );
+       if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_w_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(bishop);
+      }
+  }
+
+  if ( IsHandGold(HAND_B) ) {
+
+    if ( IsHandRook(HAND_B) )
+      {
+       BBAnd( bb, abb_b_gold_attacks[SQ_WKING],
+              abb_b_silver_attacks[SQ_WKING] );
+       BBNot( bb, bb );
+       BBAnd( bb, bb, bb_drop );
+       BBAnd( bb, bb, abb_w_gold_attacks[SQ_WKING] );
+      }
+    else { BBAnd( bb, bb_drop, abb_w_gold_attacks[SQ_WKING] ); }
+
+    while ( BBToU(bb) )
+      {
+       to = FirstOne( bb );
+       Xor( to, bb );
+       
+       if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+       bb_attacks = abb_b_gold_attacks[to];
+       if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_w_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(gold);
+      }
+  }
+  
+  if ( IsHandSilver(HAND_B) ) {
+    
+    if ( IsHandGold(HAND_B) )
+      {
+       if ( IsHandBishop(HAND_B) ) { goto b_silver_drop_end; }
+       BBNot( bb, abb_w_gold_attacks[SQ_WKING] );
+       BBAnd( bb, bb, abb_w_silver_attacks[SQ_WKING] );
+       BBAnd( bb, bb, bb_drop );
+      }
+    else {
+      BBAnd( bb, bb_drop, abb_w_silver_attacks[SQ_WKING] );
+      if ( IsHandBishop(HAND_B) )
+       {
+         BBAnd( bb, bb, abb_w_gold_attacks[SQ_WKING] );
+       }
+    }
+    
+    while ( BBToU(bb) )
+      {
+       to = FirstOne( bb );
+       Xor( to, bb );
+       
+       if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+       bb_attacks = abb_b_silver_attacks[to];
+       if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_w_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(silver);
+      }
+  }
+ b_silver_drop_end:
+  if ( IsHandKnight(HAND_B) ) {
+    
+    BBAnd( bb, bb_drop, abb_w_knight_attacks[SQ_WKING] );
+    while ( BBToU(bb) )
+      {
+       to = FirstOne( bb );
+       Xor( to, bb );
+       
+       BBIni( bb_attacks );
+       if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_w_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(knight);
+      }
+  }
+
+  /*  Moves  */
+  BBNot( bb_move, BB_BOCCUPY );
+
+  bb = BB_BDRAGON;
+  while ( BBToU(bb) ) {
+    from = FirstOne( bb );
+    Xor( from, bb );
+
+    AttackDragon( bb_attacks, from );
+    BBAnd( bb_check, bb_move,  bb_attacks );
+    BBAnd( bb_check, bb_check, abb_king_attacks[SQ_WKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    Xor( from, BB_B_HDK );
+    Xor( from, BB_B_RD );
+    Xor( from, BB_BOCCUPY );
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = FirstOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+      if ( (int)adirec[SQ_WKING][to] & flag_cross )
+       {
+         bb_attacks = abb_file_attacks[to][0];
+         bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+         BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+       }
+      else { AttackDragon( bb_attacks, to ); }
+
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      Xor( from, BB_BOCCUPY );
+      Xor( from, BB_B_RD );
+      Xor( from, BB_B_HDK );
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(-BOARD[to]) | Piece2Move(dragon) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    Xor( from, BB_BOCCUPY );
+    Xor( from, BB_B_RD );
+    Xor( from, BB_B_HDK );
+  }
+
+  bb.p[0] = BB_BROOK.p[0];
+  while ( bb.p[0] ) {
+    from = last_one0( bb.p[0] );
+    bb.p[0] ^= abb_mask[from].p[0];
+
+    AttackRook( bb_attacks, from );
+    BBAnd( bb_check, bb_move, bb_attacks );
+    BBAnd( bb_check, bb_check, abb_king_attacks[SQ_WKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    BB_B_RD.p[0]    ^= abb_mask[from].p[0];
+    BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = FirstOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+      if ( (int)adirec[SQ_WKING][to] & flag_cross )
+       {
+         bb_attacks = abb_file_attacks[to][0];
+         bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+         BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+       }
+      else { AttackDragon( bb_attacks, to ); }
+
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_B_RD.p[0]    ^= abb_mask[from].p[0];
+      return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+              | Cap2Move(-BOARD[to]) | Piece2Move(rook) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_B_RD.p[0]    ^= abb_mask[from].p[0];
+  }
+
+  bb.p[1] = BB_BROOK.p[1];
+  bb.p[2] = BB_BROOK.p[2];
+  while ( bb.p[1] | bb.p[2] ) {
+    from = first_one12( bb.p[1], bb.p[2] );
+    bb.p[1] ^= abb_mask[from].p[1];
+    bb.p[2] ^= abb_mask[from].p[2];
+
+    AttackRook( bb_attacks, from );
+    BBAnd( bb_check, bb_move, bb_attacks );
+    bb_check.p[0] &= abb_king_attacks[SQ_WKING].p[0];
+    bb_check.p[1] &= abb_b_gold_attacks[SQ_WKING].p[1];
+    bb_check.p[2] &= abb_b_gold_attacks[SQ_WKING].p[2];
+    bb_check.p[1] &= abb_w_gold_attacks[SQ_WKING].p[1];
+    bb_check.p[2] &= abb_w_gold_attacks[SQ_WKING].p[2];
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    BB_B_RD.p[1]    ^= abb_mask[from].p[1];
+    BB_B_RD.p[2]    ^= abb_mask[from].p[2];
+    BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = FirstOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+      if ( to <= I7 ) {
+       if ( (int)adirec[SQ_WKING][to] & flag_cross )
+         {
+           bb_attacks = abb_file_attacks[to][0];
+           bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+           bb_attacks.p[0] |= abb_king_attacks[to].p[0];
+           bb_attacks.p[1] |= abb_king_attacks[to].p[1];
+         }
+       else { AttackDragon( bb_attacks, to ); }
+
+      } else {
+       bb_attacks = abb_file_attacks[to][0];
+       bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+      }
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+      BB_B_RD.p[1]    ^= abb_mask[from].p[1];
+      BB_B_RD.p[2]    ^= abb_mask[from].p[2];
+      return ( To2Move(to) | From2Move(from)
+              | ( (to < A6) ? FLAG_PROMO : 0 )
+              | Cap2Move(-BOARD[to]) | Piece2Move(rook) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+    BB_B_RD.p[1]    ^= abb_mask[from].p[1];
+    BB_B_RD.p[2]    ^= abb_mask[from].p[2];
+  }
+
+  bb = BB_BHORSE;
+  while ( BBToU(bb) ) {
+    from = FirstOne( bb );
+    Xor( from, bb );
+
+    AttackHorse( bb_attacks, from );
+    BBAnd( bb_check, bb_move,  bb_attacks );
+    BBAnd( bb_check, bb_check, abb_king_attacks[SQ_WKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    Xor( from, BB_B_HDK );
+    Xor( from, BB_B_BH );
+    Xor( from, BB_BOCCUPY );
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = FirstOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+      BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+           abb_bishop_attacks_rl45[to][0] );
+      BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      Xor( from, BB_BOCCUPY );
+      Xor( from, BB_B_BH );
+      Xor( from, BB_B_HDK );
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(-BOARD[to]) | Piece2Move(horse) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    Xor( from, BB_BOCCUPY );
+    Xor( from, BB_B_BH );
+    Xor( from, BB_B_HDK );
+  }
+
+  bb.p[0] = BB_BBISHOP.p[0];
+  while ( bb.p[0] ) {
+    from = last_one0( bb.p[0] );
+    bb.p[0] ^= abb_mask[from].p[0];
+
+    AttackBishop( bb_attacks, from );
+    BBAnd( bb_check, bb_move, bb_attacks );
+    BBAnd( bb_check, bb_check, abb_king_attacks[SQ_WKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    BB_B_BH.p[0]    ^= abb_mask[from].p[0];
+    BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = FirstOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+      BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+           abb_bishop_attacks_rl45[to][0] );
+      BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_B_BH.p[0]    ^= abb_mask[from].p[0];
+      return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+              | Cap2Move(-BOARD[to]) | Piece2Move(bishop) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_B_BH.p[0]    ^= abb_mask[from].p[0];
+  }
+
+  bb.p[1] = BB_BBISHOP.p[1];
+  bb.p[2] = BB_BBISHOP.p[2];
+  while ( bb.p[1] | bb.p[2] ) {
+    from = first_one12( bb.p[1], bb.p[2] );
+    bb.p[1] ^= abb_mask[from].p[1];
+    bb.p[2] ^= abb_mask[from].p[2];
+
+    AttackBishop( bb_attacks, from );
+    BBAnd( bb_check, bb_move, bb_attacks );
+    bb_check.p[0] &= abb_king_attacks[SQ_WKING].p[0];
+    bb_check.p[1] &= abb_b_silver_attacks[SQ_WKING].p[1];
+    bb_check.p[2] &= abb_b_silver_attacks[SQ_WKING].p[2];
+    bb_check.p[1] &= abb_w_silver_attacks[SQ_WKING].p[1];
+    bb_check.p[2] &= abb_w_silver_attacks[SQ_WKING].p[2];
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    BB_B_BH.p[1]    ^= abb_mask[from].p[1];
+    BB_B_BH.p[2]    ^= abb_mask[from].p[2];
+    BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = FirstOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+      BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+           abb_bishop_attacks_rl45[to][0] );
+      if ( to <= I7 ) {
+       bb_attacks.p[0] |= abb_king_attacks[to].p[0];
+       bb_attacks.p[1] |= abb_king_attacks[to].p[1];
+      }
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+      BB_B_BH.p[1]    ^= abb_mask[from].p[1];
+      BB_B_BH.p[2]    ^= abb_mask[from].p[2];
+      return ( To2Move(to) | From2Move(from)
+              | ( (to < A6) ? FLAG_PROMO : 0 )
+              | Cap2Move(-BOARD[to]) | Piece2Move(bishop) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+    BB_B_BH.p[1]    ^= abb_mask[from].p[1];
+    BB_B_BH.p[2]    ^= abb_mask[from].p[2];
+  }
+
+  BBAnd( bb, BB_BTGOLD, b_chk_tbl[SQ_WKING].gold );
+  while ( BBToU(bb) ) {
+    from = FirstOne( bb );
+    Xor( from, bb );
+
+    BBAnd( bb_check, bb_move, abb_b_gold_attacks[from] );
+    BBAnd( bb_check, bb_check, abb_w_gold_attacks[SQ_WKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    Xor( from, BB_BTGOLD );
+    Xor( from, BB_BOCCUPY );
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = FirstOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+      bb_attacks = abb_b_gold_attacks[to];
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      Xor( from, BB_BOCCUPY );
+      Xor( from, BB_BTGOLD );
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(-BOARD[to]) | Piece2Move(BOARD[from]) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    Xor( from, BB_BOCCUPY );
+    Xor( from, BB_BTGOLD );
+  }
+
+  BBAnd( bb, BB_BSILVER, b_chk_tbl[SQ_WKING].silver );
+  while ( bb.p[0] ) {
+    from = last_one0( bb.p[0] );
+    bb.p[0] ^= abb_mask[from].p[0];
+
+    bb_check_pro.p[0] = bb_move.p[0] & abb_b_silver_attacks[from].p[0]
+      & abb_w_gold_attacks[SQ_WKING].p[0];
+    bb_check_pro.p[1] = bb_move.p[1] & abb_b_silver_attacks[from].p[1]
+      & abb_w_gold_attacks[SQ_WKING].p[1];
+
+    bb_check.p[0] = bb_move.p[0] & abb_b_silver_attacks[from].p[0]
+      & abb_w_silver_attacks[SQ_WKING].p[0]
+      & ~abb_w_gold_attacks[SQ_WKING].p[0];
+    bb_check.p[1] = bb_move.p[1] & abb_b_silver_attacks[from].p[1]
+      & abb_w_silver_attacks[SQ_WKING].p[1]
+      & ~abb_w_gold_attacks[SQ_WKING].p[1];
+
+    if ( ! ( bb_check_pro.p[0] | bb_check_pro.p[1]
+            | bb_check.p[0]| bb_check.p[1] ) ) { continue; }
+
+    BB_BSILVER.p[0] ^= abb_mask[from].p[0];
+    BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    while ( bb_check_pro.p[0] | bb_check_pro.p[1] ) {
+      to = first_one01( bb_check_pro.p[0], bb_check_pro.p[1] );
+      bb_check_pro.p[0] ^= abb_mask[to].p[0];
+      bb_check_pro.p[1] ^= abb_mask[to].p[1];
+      
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+      
+      bb_attacks = abb_b_gold_attacks[to];
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_BSILVER.p[0] ^= abb_mask[from].p[0];
+      return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+              | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+    }
+
+    while ( bb_check.p[0] | bb_check.p[1] ) {
+      to = first_one01( bb_check.p[0], bb_check.p[1] );
+      bb_check.p[0] ^= abb_mask[to].p[0];
+      bb_check.p[1] ^= abb_mask[to].p[1];
+      
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+      
+      bb_attacks = abb_b_silver_attacks[to];
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_BSILVER.p[0] ^= abb_mask[from].p[0];
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+    }
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_BSILVER.p[0] ^= abb_mask[from].p[0];
+  }
+
+  ubb = bb.p[1] & 0x7fc0000U;
+  while ( ubb ) {
+    from = last_one1( ubb );
+    ubb ^= abb_mask[from].p[1];
+
+    bb_check_pro.p[0] = bb_move.p[0] & abb_b_silver_attacks[from].p[0]
+      & abb_w_gold_attacks[SQ_WKING].p[0];
+
+    bb_check.p[0] = bb_move.p[0] & abb_b_silver_attacks[from].p[0]
+      & abb_w_silver_attacks[SQ_WKING].p[0]
+      & ~abb_w_gold_attacks[SQ_WKING].p[0];
+    bb_check.p[1] = bb_move.p[1] & abb_b_silver_attacks[from].p[1]
+      & abb_w_silver_attacks[SQ_WKING].p[1];
+
+    if ( ! (bb_check_pro.p[0]|bb_check.p[0]|bb_check.p[1]) ) { continue; }
+
+    BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+    BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    while ( bb_check_pro.p[0] ) {
+      to = last_one0( bb_check_pro.p[0] );
+      bb_check_pro.p[0] ^= abb_mask[to].p[0];
+      
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+      
+      bb_attacks = abb_b_gold_attacks[to];
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+      return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+              | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+    }
+
+    while ( bb_check.p[0] | bb_check.p[1] ) {
+      to = first_one01( bb_check.p[0], bb_check.p[1] );
+      bb_check.p[0] ^= abb_mask[to].p[0];
+      bb_check.p[1] ^= abb_mask[to].p[1];
+      
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+      
+      bb_attacks = abb_b_silver_attacks[to];
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+    }
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+  }
+
+  bb.p[1] &= 0x003ffffU;
+  while ( bb.p[1] | bb.p[2] ) {
+    from = first_one12( bb.p[1], bb.p[2] );
+    bb.p[1] ^= abb_mask[from].p[1];
+    bb.p[2] ^= abb_mask[from].p[2];
+
+    bb_check.p[1] = bb_move.p[1] & abb_b_silver_attacks[from].p[1]
+      & abb_w_silver_attacks[SQ_WKING].p[1];
+    bb_check.p[2] = bb_move.p[2] & abb_b_silver_attacks[from].p[2]
+      & abb_w_silver_attacks[SQ_WKING].p[2];
+    if ( ! ( bb_check.p[1] | bb_check.p[2] ) ) { continue; }
+
+    BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+    BB_BSILVER.p[2] ^= abb_mask[from].p[2];
+    BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = first_one12( bb_check.p[1], bb_check.p[2] );
+      bb_check.p[1] ^= abb_mask[to].p[1];
+      bb_check.p[2] ^= abb_mask[to].p[2];
+
+      if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+      bb_attacks = abb_b_silver_attacks[to];
+      if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+      BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+      BB_BSILVER.p[2] ^= abb_mask[from].p[2];
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+    } while ( bb_check.p[1] | bb_check.p[2] );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+    BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+    BB_BSILVER.p[2] ^= abb_mask[from].p[2];
+  }
+
+  BBAnd( bb, BB_BKNIGHT, b_chk_tbl[SQ_WKING].knight );
+  while ( BBToU(bb) ) {
+    from = FirstOne( bb );
+    Xor( from, bb );
+
+    bb_check.p[0] = bb_move.p[0] & abb_b_knight_attacks[from].p[0]
+      & abb_w_gold_attacks[SQ_WKING].p[0];
+
+    if ( bb_check.p[0] ) {
+      BB_BKNIGHT.p[0] ^= abb_mask[from].p[0];
+      BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+      BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+
+      do {
+       to = last_one0( bb_check.p[0] );
+       bb_check.p[0] ^= abb_mask[to].p[0];
+      
+       if ( ! is_white_attacked( ptree, to ) ) { continue; }
+      
+       bb_attacks = abb_b_gold_attacks[to];
+       if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( IsDiscoverWK( from, to ) );
+       else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+       if ( IsDiscoverBK( from, to ) )                  { continue; }
+      
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+       BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+       BB_BKNIGHT.p[0] ^= abb_mask[from].p[0];
+       BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+       return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+                | Cap2Move(-BOARD[to]) | Piece2Move(knight) );
+      } while ( bb_check.p[0] );
+
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_BKNIGHT.p[0] ^= abb_mask[from].p[0];
+      BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+    } else {
+
+      BBAnd( bb_check, bb_move, abb_b_knight_attacks[from] );
+      BBAnd( bb_check, bb_check, abb_w_knight_attacks[SQ_WKING] );
+      
+      if ( BBToU(bb_check) ) {
+       BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+       BB_BKNIGHT.p[2] ^= abb_mask[from].p[2];
+       BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+       BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       
+       do {
+         to = FirstOne( bb_check );
+         Xor( to, bb_check );
+      
+         BBIni( bb_attacks );
+         if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+         if ( IsDiscoverWK( from, to ) );
+         else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+         if ( IsDiscoverBK( from, to ) )                  { continue; }
+      
+         XorFile( from, OCCUPIED_FILE );
+         XorDiag2( from, OCCUPIED_DIAG2 );
+         XorDiag1( from, OCCUPIED_DIAG1 );
+         BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+         BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+         BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+         BB_BKNIGHT.p[2] ^= abb_mask[from].p[2];
+         return ( To2Move(to) | From2Move(from)
+                  | Cap2Move(-BOARD[to]) | Piece2Move(knight) );
+       } while ( BBToU(bb_check) );
+
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+       BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+       BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+       BB_BKNIGHT.p[2] ^= abb_mask[from].p[2];
+      }
+    }
+  }
+
+  BBAnd( bb, BB_BLANCE, b_chk_tbl[SQ_WKING].lance );
+  while ( BBToU(bb) ) {
+    from = FirstOne( bb );
+    Xor( from, bb );
+
+    bb_attacks = AttackFile(from);
+    BBAnd( bb_attacks, bb_attacks, abb_minus_rays[from] );
+    BBAnd( bb_attacks, bb_attacks, bb_move );
+
+    BBAnd( bb_check, bb_attacks, abb_mask[SQ_WKING+nfile] );
+    bb_check_pro.p[0] = bb_attacks.p[0] & abb_w_gold_attacks[SQ_WKING].p[0];
+
+    if ( ! ( bb_check_pro.p[0] | bb_check.p[0]
+            | bb_check.p[1] | bb_check.p[2] ) ) { continue; }
+
+    Xor( from, BB_BLANCE );
+    Xor( from, BB_BOCCUPY );
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    bb_check.p[0] &= 0x1ffU;
+    if ( BBToU(bb_check) ) {
+
+      to = SQ_WKING+nfile;
+      if ( ! is_white_attacked( ptree, to ) ) {
+       bb_check.p[0] &= ~abb_mask[to].p[0];
+       goto b_lance_next;
+      }
+      bb_temp = abb_file_attacks[to][0];
+      if ( can_w_king_escape( ptree, to, bb_temp ) ) { goto b_lance_next; }
+      if ( IsDiscoverWK( from, to ) );
+      else if ( can_w_piece_capture( ptree, to ) )   { goto b_lance_next; }
+      if ( IsDiscoverBK( from, to ) )               { goto b_lance_next; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      Xor( from, BB_BOCCUPY );
+      Xor( from, BB_BLANCE );
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(-BOARD[to]) | Piece2Move(lance) );
+    }
+    
+  b_lance_next:
+    while ( bb_check_pro.p[0] )
+      {
+       to = last_one0( bb_check_pro.p[0] );
+       bb_check_pro.p[0] ^= abb_mask[to].p[0];
+       
+       if ( ! is_white_attacked( ptree, to ) ) { continue; }
+       
+       bb_attacks = abb_b_gold_attacks[to];
+       if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( IsDiscoverWK( from, to ) );
+       else if ( can_w_piece_capture( ptree, to ) )      { continue; }
+       if ( IsDiscoverBK( from, to ) )                  { continue; }
+       
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       Xor( from, BB_BOCCUPY );
+       Xor( from, BB_BLANCE );
+       return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+                | Cap2Move(-BOARD[to]) | Piece2Move(lance) );
+      }
+    
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    Xor( from, BB_BOCCUPY );
+    Xor( from, BB_BLANCE );
+  }
+
+  bb_check.p[0] = bb_move.p[0] & BB_BPAWN_ATK.p[0]
+    & abb_w_gold_attacks[SQ_WKING].p[0];
+  while ( bb_check.p[0] ) {
+    to   = last_one0( bb_check.p[0] );
+    from = to + nfile;
+    bb_check.p[0] ^= abb_mask[to].p[0];
+
+    BB_BPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+    BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+    BB_BOCCUPY.p[0]   ^= abb_mask[from].p[0];
+    BB_BOCCUPY.p[1]   ^= abb_mask[from].p[1];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    if ( ! is_white_attacked( ptree, to ) )         { goto b_pawn_pro_next; }
+    bb_attacks = abb_b_gold_attacks[to];
+    if ( can_w_king_escape( ptree,to,bb_attacks ) ) { goto b_pawn_pro_next; }
+    if ( IsDiscoverWK( from, to ) );
+    else if ( can_w_piece_capture( ptree, to ) )    { goto b_pawn_pro_next; }
+    if ( IsDiscoverBK( from, to ) )                { goto b_pawn_pro_next; }
+    
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[0]   ^= abb_mask[from].p[0];
+    BB_BOCCUPY.p[1]   ^= abb_mask[from].p[1];
+    BB_BPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+    BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+    return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+            | Cap2Move(-BOARD[to]) | Piece2Move(pawn) );
+
+  b_pawn_pro_next:
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_BOCCUPY.p[0]   ^= abb_mask[from].p[0];
+    BB_BOCCUPY.p[1]   ^= abb_mask[from].p[1];
+    BB_BPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+    BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+  }
+
+  if ( SQ_WKING >= A7 && SQ_WKING <= I3 ) {
+    to   = SQ_WKING + nfile;
+    from = to        + nfile;
+    if ( BOARD[from] == pawn && BOARD[to] <= 0 ) {
+
+      BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+      BB_BPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+      BB_BOCCUPY.p[1]   ^= abb_mask[from].p[1];
+      BB_BOCCUPY.p[2]   ^= abb_mask[from].p[2];
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      
+      if ( ! is_white_attacked( ptree, to ) )         { goto b_pawn_end; }
+      BBIni( bb_attacks );
+      if ( can_w_king_escape( ptree,to,bb_attacks ) ) { goto b_pawn_end; }
+      if ( can_w_piece_capture( ptree, to ) )         { goto b_pawn_end; }
+      if ( IsDiscoverBK( from, to ) )                { goto b_pawn_end; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[1]   ^= abb_mask[from].p[1];
+      BB_BOCCUPY.p[2]   ^= abb_mask[from].p[2];
+      BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+      BB_BPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(-BOARD[to]) | Piece2Move(pawn) );
+      
+    b_pawn_end:
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_BOCCUPY.p[1]   ^= abb_mask[from].p[1];
+      BB_BOCCUPY.p[2]   ^= abb_mask[from].p[2];
+      BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+      BB_BPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+    }
+  }
+
+  return 0;
+}
+
+
+unsigned int
+is_w_mate_in_1ply( tree_t * restrict ptree )
+{
+  bitboard_t bb, bb_temp, bb_check, bb_check_pro, bb_attacks, bb_drop, bb_move;
+  unsigned int ubb;
+  int to, from, idirec;
+
+  assert( ! is_white_attacked( ptree, SQ_WKING ) );
+
+  /* Drops */
+  BBOr( bb_drop, BB_BOCCUPY, BB_WOCCUPY );
+  BBNot( bb_drop, bb_drop );
+
+  if ( IsHandRook(HAND_W) ) {
+
+    BBAnd( bb, abb_w_gold_attacks[SQ_BKING],
+          abb_b_gold_attacks[SQ_BKING] );
+    BBAnd( bb, bb, bb_drop );
+    while( BBToU(bb) )
+      {
+       to = LastOne( bb );
+       Xor( to, bb );
+
+       if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+       bb_attacks                     = abb_file_attacks[to][0];
+       bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+       if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_b_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(rook);
+      }
+
+  } else if ( IsHandLance(HAND_W) && SQ_BKING >= A8 ) {
+
+    to = SQ_BKING-nfile;
+    if ( ( ! BOARD[to] ) && is_black_attacked( ptree, to ) )
+      {
+       bb_attacks = abb_file_attacks[to][0];
+       if ( ( ! can_b_king_escape( ptree, to, bb_attacks ) )
+            && ( ! can_b_piece_capture( ptree, to ) ) )
+         {
+           return To2Move(to) | Drop2Move(lance);
+         }
+      }
+  }
+
+  if ( IsHandBishop(HAND_W) ) {
+
+    BBAnd( bb, abb_w_silver_attacks[SQ_BKING],
+          abb_b_silver_attacks[SQ_BKING] );
+    BBAnd( bb, bb, bb_drop );
+    while( BBToU(bb) )
+      {
+       to = LastOne( bb );
+       Xor( to, bb );
+
+       if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+       BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+             abb_bishop_attacks_rl45[to][0] );
+       if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_b_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(bishop);
+      }
+  }
+
+  if ( IsHandGold(HAND_W) ) {
+    
+    if ( IsHandRook(HAND_W) )
+      {
+       BBAnd( bb, abb_w_gold_attacks[SQ_BKING],
+              abb_w_silver_attacks[SQ_BKING] );
+       BBNot( bb, bb );
+       BBAnd( bb, bb, bb_drop );
+       BBAnd( bb, bb, abb_b_gold_attacks[SQ_BKING] );
+      }
+    else { BBAnd( bb, bb_drop, abb_b_gold_attacks[SQ_BKING] ); }
+
+    while ( BBToU(bb) )
+      {
+       to = LastOne( bb );
+       Xor( to, bb );
+       
+       if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+       bb_attacks = abb_w_gold_attacks[to];
+       if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_b_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(gold);
+      }
+  }
+  
+  if ( IsHandSilver(HAND_W) ) {
+    
+    if ( IsHandGold(HAND_W) )
+      {
+       if ( IsHandBishop(HAND_W) ) { goto w_silver_drop_end; }
+       BBNot( bb, abb_b_gold_attacks[SQ_BKING] );
+       BBAnd( bb, bb, abb_b_silver_attacks[SQ_BKING] );
+       BBAnd( bb, bb, bb_drop );
+      }
+    else {
+      BBAnd( bb, bb_drop, abb_b_silver_attacks[SQ_BKING] );
+      if ( IsHandBishop(HAND_W) )
+       {
+         BBAnd( bb, bb, abb_b_gold_attacks[SQ_BKING] );
+       }
+    }
+    
+    while ( BBToU(bb) )
+      {
+       to = LastOne( bb );
+       Xor( to, bb );
+       
+       if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+       bb_attacks = abb_w_silver_attacks[to];
+       if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_b_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(silver);
+      }
+  }
+ w_silver_drop_end:
+  
+  if ( IsHandKnight(HAND_W) ) {
+    
+    BBAnd( bb, bb_drop, abb_b_knight_attacks[SQ_BKING] );
+    while ( BBToU(bb) )
+      {
+       to = LastOne( bb );
+       Xor( to, bb );
+       
+       BBIni( bb_attacks );
+       if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( can_b_piece_capture( ptree, to ) )           { continue; }
+       return To2Move(to) | Drop2Move(knight);
+      }
+  }
+
+  /* Moves */
+  BBNot( bb_move, BB_WOCCUPY );
+
+  bb = BB_WDRAGON;
+  while ( BBToU(bb) ) {
+    from = LastOne( bb );
+    Xor( from, bb );
+
+    AttackDragon( bb_attacks, from );
+    BBAnd( bb_check, bb_move,  bb_attacks );
+    BBAnd( bb_check, bb_check, abb_king_attacks[SQ_BKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    Xor( from, BB_W_HDK );
+    Xor( from, BB_W_RD );
+    Xor( from, BB_WOCCUPY );
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = LastOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+      if ( (int)adirec[SQ_BKING][to] & flag_cross )
+       {
+         bb_attacks = abb_file_attacks[to][0];
+         bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+         BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+       }
+      else { AttackDragon( bb_attacks, to ); }
+
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      Xor( from, BB_WOCCUPY );
+      Xor( from, BB_W_RD );
+      Xor( from, BB_W_HDK );
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(BOARD[to]) | Piece2Move(dragon) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    Xor( from, BB_WOCCUPY );
+    Xor( from, BB_W_RD );
+    Xor( from, BB_W_HDK );
+  }
+
+  bb.p[2] = BB_WROOK.p[2];
+  while ( bb.p[2] ) {
+    from = first_one2( bb.p[2] );
+    bb.p[2] ^= abb_mask[from].p[2];
+
+    AttackRook( bb_attacks, from );
+    BBAnd( bb_check, bb_move, bb_attacks );
+    BBAnd( bb_check, bb_check, abb_king_attacks[SQ_BKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    BB_W_RD.p[2]    ^= abb_mask[from].p[2];
+    BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = LastOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+      if ( (int)adirec[SQ_BKING][to] & flag_cross )
+       {
+         bb_attacks = abb_file_attacks[to][0];
+         bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+         BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+       }
+      else { AttackDragon( bb_attacks, to ); }
+
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+      BB_W_RD.p[2]    ^= abb_mask[from].p[2];
+      return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+              | Cap2Move(BOARD[to]) | Piece2Move(rook) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+    BB_W_RD.p[2]    ^= abb_mask[from].p[2];
+  }
+
+  bb.p[0] = BB_WROOK.p[0];
+  bb.p[1] = BB_WROOK.p[1];
+  while ( bb.p[0] | bb.p[1] ) {
+    from = last_one01( bb.p[0], bb.p[1] );
+    bb.p[0] ^= abb_mask[from].p[0];
+    bb.p[1] ^= abb_mask[from].p[1];
+
+    AttackRook( bb_attacks, from );
+    BBAnd( bb_check, bb_move, bb_attacks );
+    bb_check.p[0] &= abb_b_gold_attacks[SQ_BKING].p[0];
+    bb_check.p[1] &= abb_b_gold_attacks[SQ_BKING].p[1];
+    bb_check.p[0] &= abb_w_gold_attacks[SQ_BKING].p[0];
+    bb_check.p[1] &= abb_w_gold_attacks[SQ_BKING].p[1];
+    bb_check.p[2] &= abb_king_attacks[SQ_BKING].p[2];
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    BB_W_RD.p[0]    ^= abb_mask[from].p[0];
+    BB_W_RD.p[1]    ^= abb_mask[from].p[1];
+    BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = LastOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+      if ( to >= A3 ) {
+       if ( (int)adirec[SQ_BKING][to] & flag_cross )
+         {
+           bb_attacks = abb_file_attacks[to][0];
+           bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+           bb_attacks.p[1] |= abb_king_attacks[to].p[1];
+           bb_attacks.p[2] |= abb_king_attacks[to].p[2];
+         }
+       else { AttackDragon( bb_attacks, to ); }
+      } else {
+       bb_attacks = abb_file_attacks[to][0];
+       bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+      }
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_W_RD.p[0]    ^= abb_mask[from].p[0];
+      BB_W_RD.p[1]    ^= abb_mask[from].p[1];
+      return ( To2Move(to) | From2Move(from)
+              | ( (to > I4) ? FLAG_PROMO : 0 )
+              | Cap2Move(BOARD[to]) | Piece2Move(rook) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_W_RD.p[0]    ^= abb_mask[from].p[0];
+    BB_W_RD.p[1]    ^= abb_mask[from].p[1];
+  }
+
+  bb = BB_WHORSE;
+  while ( BBToU(bb) ) {
+    from = LastOne( bb );
+    Xor( from, bb );
+
+    AttackHorse( bb_attacks, from );
+    BBAnd( bb_check, bb_move,  bb_attacks );
+    BBAnd( bb_check, bb_check, abb_king_attacks[SQ_BKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    Xor( from, BB_W_HDK );
+    Xor( from, BB_W_BH );
+    Xor( from, BB_WOCCUPY );
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = LastOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+      BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+           abb_bishop_attacks_rl45[to][0] );
+      BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      Xor( from, BB_WOCCUPY );
+      Xor( from, BB_W_BH );
+      Xor( from, BB_W_HDK );
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(BOARD[to]) | Piece2Move(horse) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    Xor( from, BB_WOCCUPY );
+    Xor( from, BB_W_BH );
+    Xor( from, BB_W_HDK );
+  }
+
+  bb.p[2] = BB_WBISHOP.p[2];
+  while ( bb.p[2] ) {
+    from = first_one2( bb.p[2] );
+    bb.p[2] ^= abb_mask[from].p[2];
+
+    AttackBishop( bb_attacks, from );
+    BBAnd( bb_check, bb_move, bb_attacks );
+    BBAnd( bb_check, bb_check, abb_king_attacks[SQ_BKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    BB_W_BH.p[2]    ^= abb_mask[from].p[2];
+    BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = LastOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+      BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+           abb_bishop_attacks_rl45[to][0] );
+      BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+      BB_W_BH.p[2]    ^= abb_mask[from].p[2];
+      return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+              | Cap2Move(BOARD[to]) | Piece2Move(bishop) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+    BB_W_BH.p[2]    ^= abb_mask[from].p[2];
+  }
+
+  bb.p[0] = BB_WBISHOP.p[0];
+  bb.p[1] = BB_WBISHOP.p[1];
+  while ( bb.p[0] | bb.p[1] ) {
+    from = last_one01( bb.p[0], bb.p[1] );
+    bb.p[0] ^= abb_mask[from].p[0];
+    bb.p[1] ^= abb_mask[from].p[1];
+
+    AttackBishop( bb_attacks, from );
+    BBAnd( bb_check, bb_move, bb_attacks );
+    bb_check.p[0] &= abb_b_silver_attacks[SQ_BKING].p[0];
+    bb_check.p[1] &= abb_b_silver_attacks[SQ_BKING].p[1];
+    bb_check.p[0] &= abb_w_silver_attacks[SQ_BKING].p[0];
+    bb_check.p[1] &= abb_w_silver_attacks[SQ_BKING].p[1];
+    bb_check.p[2] &= abb_king_attacks[SQ_BKING].p[2];
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    BB_W_BH.p[0]    ^= abb_mask[from].p[0];
+    BB_W_BH.p[1]    ^= abb_mask[from].p[1];
+    BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = LastOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+      BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+           abb_bishop_attacks_rl45[to][0] );
+      if ( to >= A3 ) {
+       bb_attacks.p[1] |= abb_king_attacks[to].p[1];
+       bb_attacks.p[2] |= abb_king_attacks[to].p[2];
+      }
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_W_BH.p[0]    ^= abb_mask[from].p[0];
+      BB_W_BH.p[1]    ^= abb_mask[from].p[1];
+      return ( To2Move(to) | From2Move(from)
+              | ( (to > I4) ? FLAG_PROMO : 0 )
+              | Cap2Move(BOARD[to]) | Piece2Move(bishop) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_W_BH.p[0]    ^= abb_mask[from].p[0];
+    BB_W_BH.p[1]    ^= abb_mask[from].p[1];
+  }
+
+  BBAnd( bb, BB_WTGOLD, w_chk_tbl[SQ_BKING].gold );
+  while ( BBToU(bb) ) {
+    from = LastOne( bb );
+    Xor( from, bb );
+
+    BBAnd( bb_check, bb_move, abb_w_gold_attacks[from] );
+    BBAnd( bb_check, bb_check, abb_b_gold_attacks[SQ_BKING] );
+    if ( ! BBToU(bb_check) ) { continue; }
+
+    Xor( from, BB_WTGOLD );
+    Xor( from, BB_WOCCUPY );
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = LastOne( bb_check );
+      Xor( to, bb_check );
+
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+      bb_attacks = abb_w_gold_attacks[to];
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      Xor( from, BB_WOCCUPY );
+      Xor( from, BB_WTGOLD );
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(BOARD[to]) | Piece2Move(-BOARD[from]) );
+    } while ( BBToU(bb_check) );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    Xor( from, BB_WOCCUPY );
+    Xor( from, BB_WTGOLD );
+  }
+
+  BBAnd( bb, BB_WSILVER, w_chk_tbl[SQ_BKING].silver );
+  while ( bb.p[2] ) {
+    from = first_one2( bb.p[2] );
+    bb.p[2] ^= abb_mask[from].p[2];
+
+    bb_check_pro.p[1] = bb_move.p[1] & abb_w_silver_attacks[from].p[1]
+      & abb_b_gold_attacks[SQ_BKING].p[1];
+    bb_check_pro.p[2] = bb_move.p[2] & abb_w_silver_attacks[from].p[2]
+      & abb_b_gold_attacks[SQ_BKING].p[2];
+
+    bb_check.p[1] = bb_move.p[1] & abb_w_silver_attacks[from].p[1]
+      & abb_b_silver_attacks[SQ_BKING].p[1]
+      & ~abb_b_gold_attacks[SQ_BKING].p[1];
+    bb_check.p[2] = bb_move.p[2] & abb_w_silver_attacks[from].p[2]
+      & abb_b_silver_attacks[SQ_BKING].p[2]
+      & ~abb_b_gold_attacks[SQ_BKING].p[2];
+
+    if ( ! ( bb_check_pro.p[1] | bb_check_pro.p[2]
+            | bb_check.p[1]| bb_check.p[2] ) ) { continue; }
+
+    BB_WSILVER.p[2] ^= abb_mask[from].p[2];
+    BB_WOCCUPY.p[2]  ^= abb_mask[from].p[2];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    while ( bb_check_pro.p[1] | bb_check_pro.p[2] ) {
+      to = last_one12( bb_check_pro.p[1], bb_check_pro.p[2] );
+      bb_check_pro.p[1] ^= abb_mask[to].p[1];
+      bb_check_pro.p[2] ^= abb_mask[to].p[2];
+      
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+      
+      bb_attacks = abb_w_gold_attacks[to];
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[2]  ^= abb_mask[from].p[2];
+      BB_WSILVER.p[2] ^= abb_mask[from].p[2];
+      return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+              | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+    }
+
+    while ( bb_check.p[1] | bb_check.p[2] ) {
+      to = last_one12( bb_check.p[1], bb_check.p[2] );
+      bb_check.p[1] ^= abb_mask[to].p[1];
+      bb_check.p[2] ^= abb_mask[to].p[2];
+      
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+      
+      bb_attacks = abb_w_silver_attacks[to];
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[2]  ^= abb_mask[from].p[2];
+      BB_WSILVER.p[2] ^= abb_mask[from].p[2];
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+    }
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[2]  ^= abb_mask[from].p[2];
+    BB_WSILVER.p[2] ^= abb_mask[from].p[2];
+  }
+
+  ubb = bb.p[1] & 0x1ffU;
+  while ( ubb ) {
+    from = first_one1( ubb );
+    ubb ^= abb_mask[from].p[1];
+
+    bb_check_pro.p[2] = bb_move.p[2] & abb_w_silver_attacks[from].p[2]
+      & abb_b_gold_attacks[SQ_BKING].p[2];
+
+    bb_check.p[2] = bb_move.p[2] & abb_w_silver_attacks[from].p[2]
+      & abb_b_silver_attacks[SQ_BKING].p[2]
+      & ~abb_b_gold_attacks[SQ_BKING].p[2];
+    bb_check.p[1] = bb_move.p[1] & abb_w_silver_attacks[from].p[1]
+      & abb_b_silver_attacks[SQ_BKING].p[1];
+
+    if ( ! (bb_check_pro.p[2]|bb_check.p[2]|bb_check.p[1]) ) { continue; }
+
+    BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+    BB_WOCCUPY.p[1]  ^= abb_mask[from].p[1];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    while ( bb_check_pro.p[2] ) {
+      to = first_one2( bb_check_pro.p[2] );
+      bb_check_pro.p[2] ^= abb_mask[to].p[2];
+      
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+      
+      bb_attacks = abb_w_gold_attacks[to];
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+      return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+              | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+    }
+
+    while ( bb_check.p[1] | bb_check.p[2] ) {
+      to = last_one12( bb_check.p[1], bb_check.p[2] );
+      bb_check.p[1] ^= abb_mask[to].p[1];
+      bb_check.p[2] ^= abb_mask[to].p[2];
+      
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+      
+      bb_attacks = abb_w_silver_attacks[to];
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                  { continue; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+    }
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+  }
+
+  bb.p[0] = bb.p[0];
+  bb.p[1] = bb.p[1] & 0x7fffe00U;
+  while ( bb.p[0] | bb.p[1] ) {
+    from = last_one01( bb.p[0], bb.p[1] );
+    bb.p[0] ^= abb_mask[from].p[0];
+    bb.p[1] ^= abb_mask[from].p[1];
+
+    bb_check.p[0] = bb_move.p[0] & abb_w_silver_attacks[from].p[0]
+      & abb_b_silver_attacks[SQ_BKING].p[0];
+    bb_check.p[1] = bb_move.p[1] & abb_w_silver_attacks[from].p[1]
+      & abb_b_silver_attacks[SQ_BKING].p[1];
+    if ( ! ( bb_check.p[0] | bb_check.p[1] ) ) { continue; }
+
+    BB_WSILVER.p[0] ^= abb_mask[from].p[0];
+    BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+    BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    do {
+      to = last_one01( bb_check.p[0], bb_check.p[1] );
+      bb_check.p[0] ^= abb_mask[to].p[0];
+      bb_check.p[1] ^= abb_mask[to].p[1];
+
+      if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+      bb_attacks = abb_w_silver_attacks[to];
+      if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+      if ( IsDiscoverWK( from, to ) )                   { continue; }
+       
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+      BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_WSILVER.p[0] ^= abb_mask[from].p[0];
+      BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+    } while ( bb_check.p[0] | bb_check.p[1] );
+
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+    BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+    BB_WSILVER.p[0] ^= abb_mask[from].p[0];
+    BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+  }
+
+  BBAnd( bb, BB_WKNIGHT, w_chk_tbl[SQ_BKING].knight );
+  while ( BBToU(bb) ) {
+    from = LastOne( bb );
+    Xor( from, bb );
+
+    bb_check.p[2] = bb_move.p[2] & abb_w_knight_attacks[from].p[2]
+      & abb_b_gold_attacks[SQ_BKING].p[2];
+
+    if ( bb_check.p[2] ) {
+      BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+      BB_WKNIGHT.p[2] ^= abb_mask[from].p[2];
+      BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+
+      do {
+       to = first_one2( bb_check.p[2] );
+       bb_check.p[2] ^= abb_mask[to].p[2];
+      
+       if ( ! is_black_attacked( ptree, to ) ) { continue; }
+      
+       bb_attacks = abb_w_gold_attacks[to];
+       if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( IsDiscoverBK( from, to ) );
+       else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+       if ( IsDiscoverWK( from, to ) )                   { continue; }
+      
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+       BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+       BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+       BB_WKNIGHT.p[2] ^= abb_mask[from].p[2];
+       return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+                | Cap2Move(BOARD[to]) | Piece2Move(knight) );
+      } while ( bb_check.p[2] );
+
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+      BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+      BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+      BB_WKNIGHT.p[2] ^= abb_mask[from].p[2];
+    } else {
+
+      BBAnd( bb_check, bb_move, abb_w_knight_attacks[from] );
+      BBAnd( bb_check, bb_check, abb_b_knight_attacks[SQ_BKING] );
+      
+      if ( BBToU(bb_check) ) {
+       BB_WKNIGHT.p[0] ^= abb_mask[from].p[0];
+       BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+       BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+       BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       
+       do {
+         to = LastOne( bb_check );
+         Xor( to, bb_check );
+      
+         BBIni( bb_attacks );
+         if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+         if ( IsDiscoverBK( from, to ) );
+         else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+         if ( IsDiscoverWK( from, to ) )                   { continue; }
+      
+         XorFile( from, OCCUPIED_FILE );
+         XorDiag2( from, OCCUPIED_DIAG2 );
+         XorDiag1( from, OCCUPIED_DIAG1 );
+         BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+         BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+         BB_WKNIGHT.p[0] ^= abb_mask[from].p[0];
+         BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+         return ( To2Move(to) | From2Move(from)
+                  | Cap2Move(BOARD[to]) | Piece2Move(knight) );
+       } while ( BBToU(bb_check) );
+
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+       BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+       BB_WKNIGHT.p[0] ^= abb_mask[from].p[0];
+       BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+      }
+    }
+  }
+
+  BBAnd( bb, BB_WLANCE, w_chk_tbl[SQ_BKING].lance );
+  while ( BBToU(bb) ) {
+    from = LastOne( bb );
+    Xor( from, bb );
+
+    bb_attacks = AttackFile(from);
+    BBAnd( bb_attacks, bb_attacks, abb_plus_rays[from] );
+    BBAnd( bb_attacks, bb_attacks, bb_move );
+
+    BBAnd( bb_check, bb_attacks, abb_mask[SQ_BKING-nfile] );
+    bb_check_pro.p[2] = bb_attacks.p[2] & abb_b_gold_attacks[SQ_BKING].p[2];
+
+    if ( ! ( bb_check_pro.p[2] | bb_check.p[0]
+            | bb_check.p[1] | bb_check.p[2] ) ) { continue; }
+
+    Xor( from, BB_WLANCE );
+    Xor( from, BB_WOCCUPY );
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    bb_check.p[2] &= 0x7fc0000U;
+    if ( BBToU(bb_check) ) {
+
+      to = SQ_BKING-nfile;
+      if ( ! is_black_attacked( ptree, to ) ) {
+       bb_check.p[2] &= ~abb_mask[to].p[2];
+       goto w_lance_next;
+      }
+      bb_temp = abb_file_attacks[to][0];
+      if ( can_b_king_escape( ptree, to, bb_temp ) ) { goto w_lance_next; }
+      if ( IsDiscoverBK( from, to ) );
+      else if ( can_b_piece_capture( ptree, to ) )   { goto w_lance_next; }
+      if ( IsDiscoverWK( from, to ) )                { goto w_lance_next; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      Xor( from, BB_WOCCUPY );
+      Xor( from, BB_WLANCE );
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(BOARD[to]) | Piece2Move(lance) );
+    }
+    
+  w_lance_next:
+    while ( bb_check_pro.p[2] )
+      {
+       to = first_one2( bb_check_pro.p[2] );
+       bb_check_pro.p[2] ^= abb_mask[to].p[2];
+       
+       if ( ! is_black_attacked( ptree, to ) ) { continue; }
+       
+       bb_attacks = abb_w_gold_attacks[to];
+       if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+       if ( IsDiscoverBK( from, to ) );
+       else if ( can_b_piece_capture( ptree, to ) )      { continue; }
+       if ( IsDiscoverWK( from, to ) )                   { continue; }
+       
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       Xor( from, BB_WOCCUPY );
+       Xor( from, BB_WLANCE );
+       return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+                | Cap2Move(BOARD[to]) | Piece2Move(lance) );
+      }
+    
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    Xor( from, BB_WOCCUPY );
+    Xor( from, BB_WLANCE );
+  }
+
+  bb_check.p[2] = bb_move.p[2] & BB_WPAWN_ATK.p[2]
+    & abb_b_gold_attacks[SQ_BKING].p[2];
+  while ( bb_check.p[2] ) {
+    to   = first_one2( bb_check.p[2] );
+    from = to - nfile;
+    bb_check.p[2] ^= abb_mask[to].p[2];
+
+    BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+    BB_WPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+    BB_WOCCUPY.p[1]   ^= abb_mask[from].p[1];
+    BB_WOCCUPY.p[2]   ^= abb_mask[from].p[2];
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+
+    if ( ! is_black_attacked( ptree, to ) )         { goto w_pawn_pro_next; }
+    bb_attacks = abb_w_gold_attacks[to];
+    if ( can_b_king_escape( ptree,to,bb_attacks ) ) { goto w_pawn_pro_next; }
+    if ( IsDiscoverBK( from, to ) );
+    else if ( can_b_piece_capture( ptree, to ) )    { goto w_pawn_pro_next; }
+    if ( IsDiscoverWK( from, to ) )                 { goto w_pawn_pro_next; }
+    
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[1]   ^= abb_mask[from].p[1];
+    BB_WOCCUPY.p[2]   ^= abb_mask[from].p[2];
+    BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+    BB_WPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+    return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+            | Cap2Move(BOARD[to]) | Piece2Move(pawn) );
+
+  w_pawn_pro_next:
+    XorFile( from, OCCUPIED_FILE );
+    XorDiag2( from, OCCUPIED_DIAG2 );
+    XorDiag1( from, OCCUPIED_DIAG1 );
+    BB_WOCCUPY.p[1]   ^= abb_mask[from].p[1];
+    BB_WOCCUPY.p[2]   ^= abb_mask[from].p[2];
+    BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+    BB_WPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+  }
+
+  if ( SQ_BKING <= I3 && SQ_BKING >= A7 ) {
+    to   = SQ_BKING - nfile;
+    from = to        - nfile;
+    if ( BOARD[from] == -pawn && BOARD[to] >= 0 ) {
+
+      BB_WPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+      BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+      BB_WOCCUPY.p[0]   ^= abb_mask[from].p[0];
+      BB_WOCCUPY.p[1]   ^= abb_mask[from].p[1];
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      
+      if ( ! is_black_attacked( ptree, to ) )         { goto w_pawn_end; }
+      BBIni( bb_attacks );
+      if ( can_b_king_escape( ptree,to,bb_attacks ) ) { goto w_pawn_end; }
+      if ( can_b_piece_capture( ptree, to ) )         { goto w_pawn_end; }
+      if ( IsDiscoverWK( from, to ) )                 { goto w_pawn_end; }
+      
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[0]   ^= abb_mask[from].p[0];
+      BB_WOCCUPY.p[1]   ^= abb_mask[from].p[1];
+      BB_WPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+      BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+      return ( To2Move(to) | From2Move(from)
+              | Cap2Move(BOARD[to]) | Piece2Move(pawn) );
+      
+    w_pawn_end:
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      BB_WOCCUPY.p[0]   ^= abb_mask[from].p[0];
+      BB_WOCCUPY.p[1]   ^= abb_mask[from].p[1];
+      BB_WPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+      BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+    }
+  }
+
+  return 0;
+}
+
+
+static int
+can_w_piece_capture( const tree_t * restrict ptree, int to )
+{
+  bitboard_t bb_sum, bb, bb_attacks;
+  int idirec, from;
+  
+  from = to-nfile;
+  if ( to >= A8 && BOARD[from] == -pawn )
+    {
+      if ( IsDiscoverWK(from,to) );
+      else { return 1; }
+    }
+  
+  BBAnd( bb_sum, BB_WKNIGHT, abb_b_knight_attacks[to] );
+  
+  BBAnd( bb, BB_WSILVER, abb_b_silver_attacks[to] );
+  BBOr( bb_sum, bb, bb_sum );
+  
+  BBAnd( bb, BB_WTGOLD, abb_b_gold_attacks[to] );
+  BBOr( bb_sum, bb, bb_sum );
+
+  BBOr( bb, BB_WHORSE, BB_WDRAGON );
+  BBAnd( bb, bb, abb_king_attacks[to] );
+  BBOr( bb_sum, bb, bb_sum );
+  
+  AttackBishop( bb, to );
+  BBAnd( bb, BB_W_BH, bb );
+  BBOr( bb_sum, bb, bb_sum );
+
+  bb_sum.p[aslide[to].ir0] |= BB_W_RD.p[aslide[to].ir0] & AttackRank(to);
+
+  BBAnd( bb, BB_WLANCE, abb_minus_rays[to] );
+  BBOr( bb, bb, BB_W_RD );
+  bb_attacks = AttackFile( to );
+  BBAnd( bb, bb, bb_attacks );
+  BBOr( bb_sum, bb_sum, bb );
+
+  while ( BBToU( bb_sum ) )
+    {
+      from  = FirstOne( bb_sum );
+      Xor( from, bb_sum );
+
+      if ( IsDiscoverWK(from,to) ) { continue; }
+      return 1;
+    }
+
+  return 0;
+}
+
+
+static int
+can_b_piece_capture( const tree_t * restrict ptree, int to )
+{
+  bitboard_t bb_sum, bb, bb_attacks;
+  int idirec, from;
+
+  from = to+nfile;
+  if ( to <= I2 && BOARD[from] == pawn )
+    {
+      if ( IsDiscoverBK(from,to) );
+      else { return 1; }
+    }
+
+  BBAnd( bb_sum, BB_BKNIGHT, abb_w_knight_attacks[to] );
+
+  BBAnd( bb, BB_BSILVER, abb_w_silver_attacks[to] );
+  BBOr( bb_sum, bb_sum, bb );
+
+  BBAnd( bb, BB_BTGOLD, abb_w_gold_attacks[to] );
+  BBOr( bb_sum, bb_sum, bb );
+
+  BBOr( bb, BB_BHORSE, BB_BDRAGON );
+  BBAnd( bb, bb, abb_king_attacks[to] );
+  BBOr( bb_sum, bb_sum, bb );
+  
+  AttackBishop( bb, to );
+  BBAnd( bb, bb, BB_B_BH );
+  BBOr( bb_sum, bb_sum, bb );
+
+  bb_sum.p[aslide[to].ir0] |= BB_B_RD.p[aslide[to].ir0] & AttackRank(to);
+
+  BBAnd( bb, BB_BLANCE, abb_plus_rays[to] );
+  BBOr( bb, bb, BB_B_RD );
+  bb_attacks = AttackFile( to );
+  BBAnd( bb, bb, bb_attacks );
+  BBOr( bb_sum, bb_sum, bb );
+
+  while ( BBToU( bb_sum ) )
+    {
+      from  = LastOne( bb_sum );
+      Xor( from, bb_sum );
+
+      if ( IsDiscoverBK( from, to ) ) { continue; }
+      return 1;
+    }
+
+  return 0;
+}
+
+
+static int
+can_w_king_escape( tree_t * restrict ptree, int to, bitboard_t bb )
+{
+  int iret = 0, iescape;
+
+  if ( !BOARD[to] )
+    {
+      Xor( to, BB_BOCCUPY );
+      XorFile( to, OCCUPIED_FILE );
+      XorDiag2( to, OCCUPIED_DIAG2 );
+      XorDiag1( to, OCCUPIED_DIAG1 );
+    }
+  Xor( SQ_WKING, BB_WOCCUPY );
+  XorFile( SQ_WKING, OCCUPIED_FILE );
+  XorDiag2( SQ_WKING, OCCUPIED_DIAG2 );
+  XorDiag1( SQ_WKING, OCCUPIED_DIAG1 );
+
+  BBOr( bb, bb, abb_mask[to] );
+  BBOr( bb, bb, BB_WOCCUPY );
+  BBNot( bb, bb );
+  BBAnd( bb, bb, abb_king_attacks[SQ_WKING] );
+  
+  while( BBToU(bb) )
+    {
+      iescape = FirstOne( bb );
+      if ( ! is_white_attacked( ptree, iescape ) )
+       {
+         iret = 1;
+         break;
+       }
+      Xor( iescape, bb );
+    }
+
+  XorFile( SQ_WKING, OCCUPIED_FILE );
+  XorDiag2( SQ_WKING, OCCUPIED_DIAG2 );
+  XorDiag1( SQ_WKING, OCCUPIED_DIAG1 );
+  Xor( SQ_WKING, BB_WOCCUPY );
+  if ( !BOARD[to] )
+    {
+      Xor( to, BB_BOCCUPY );
+      XorFile( to, OCCUPIED_FILE );
+      XorDiag2( to, OCCUPIED_DIAG2 );
+      XorDiag1( to, OCCUPIED_DIAG1 );
+    }
+
+  return iret;
+}
+
+
+static int
+can_b_king_escape( tree_t * restrict ptree, int to, bitboard_t bb )
+{
+  int iret = 0, iescape;
+
+  if ( !BOARD[to] )
+    {
+      Xor( to, BB_WOCCUPY );
+      XorFile( to, OCCUPIED_FILE );
+      XorDiag2( to, OCCUPIED_DIAG2 );
+      XorDiag1( to, OCCUPIED_DIAG1 );
+    }
+
+  Xor( SQ_BKING, BB_BOCCUPY );
+  XorFile( SQ_BKING, OCCUPIED_FILE );
+  XorDiag2( SQ_BKING, OCCUPIED_DIAG2 );
+  XorDiag1( SQ_BKING, OCCUPIED_DIAG1 );
+
+  BBOr( bb, bb, abb_mask[to] );
+  BBOr( bb, bb, BB_BOCCUPY );
+  BBNot( bb, bb );
+  BBAnd( bb, bb, abb_king_attacks[SQ_BKING] );
+  
+  while( BBToU(bb) )
+    {
+      iescape = LastOne( bb );
+      if ( ! is_black_attacked( ptree, iescape ) )
+       {
+         iret = 1;
+         break;
+       }
+      Xor( iescape, bb );
+    }
+
+  XorFile( SQ_BKING, OCCUPIED_FILE );
+  XorDiag2( SQ_BKING, OCCUPIED_DIAG2 );
+  XorDiag1( SQ_BKING, OCCUPIED_DIAG1 );
+  Xor( SQ_BKING, BB_BOCCUPY );
+
+  if ( !BOARD[to] )
+    {
+      XorFile( to, OCCUPIED_FILE );
+      XorDiag2( to, OCCUPIED_DIAG2 );
+      XorDiag1( to, OCCUPIED_DIAG1 );
+      Xor( to, BB_WOCCUPY );
+    }
+
+  return iret;
+}
diff --git a/mate3.c b/mate3.c
new file mode 100644 (file)
index 0000000..61d1036
--- /dev/null
+++ b/mate3.c
@@ -0,0 +1,792 @@
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+#include "shogi.h"
+
+enum { mate_king_cap_checker = 0,
+       mate_cap_checker_gen,
+       mate_cap_checker,
+       mate_king_cap_gen,
+       mate_king_cap,
+       mate_king_move_gen,
+       mate_king_move,
+       mate_intercept_move_gen,
+       mate_intercept_move,
+       mate_intercept_weak_move,
+       mate_intercept_drop_sup };
+
+static int mate3_and( tree_t * restrict ptree, int turn, int ply, int flag );
+static void checker( const tree_t * restrict ptree, char *psq, int turn );
+static unsigned int gen_king_cap_checker( const tree_t * restrict ptree,
+                                         int to, int turn );
+static int mate_weak_or( tree_t * restrict ptree, int turn, int ply,
+                        int from, int to );
+static unsigned int *gen_move_to( const tree_t * restrict ptree, int sq,
+                                 int turn, unsigned int * restrict pmove );
+static unsigned int *gen_king_move( const tree_t * restrict ptree,
+                                   const char *psq, int turn, int is_capture,
+                                   unsigned int * restrict pmove );
+static unsigned int *gen_intercept( tree_t * restrict __ptree__,
+                                   int sq_checker, int ply, int turn,
+                                   int * restrict premaining,
+                                   unsigned int * restrict pmove, int flag );
+static int gen_next_evasion_mate( tree_t * restrict ptree, const char *psq,
+                                 int ply, int turn, int flag );
+
+unsigned int
+is_mate_in3ply( tree_t * restrict ptree, int turn, int ply )
+{
+  int value, flag_skip;
+
+  if ( ply >= PLY_MAX-2 ) { return 0; }
+
+  flag_skip = 0;
+
+  ptree->anext_move[ply].move_last = ptree->move_last[ply-1];
+  ptree->move_last[ply] = GenCheck( turn, ptree->move_last[ply-1] );
+
+  while ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+    {
+      MOVE_CURR = *ptree->anext_move[ply].move_last++;
+
+      if ( MOVE_CURR & MOVE_CHK_CLEAR ) { flag_skip = 0; }
+      if ( flag_skip ) { continue; }
+
+      assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+      MakeMove( turn, MOVE_CURR, ply );
+      if ( InCheck(turn) )
+       {
+         UnMakeMove( turn, MOVE_CURR, ply );
+         continue;
+       }
+
+      value = mate3_and( ptree, Flip(turn), ply+1, 0 );
+      
+      UnMakeMove( turn, MOVE_CURR, ply );
+
+      if ( value ) { return 1; }
+
+      if ( ( MOVE_CURR & MOVE_CHK_SET )
+          && I2To(MOVE_CURR) != I2To(ptree->current_move[ply+1]) )
+       {
+         flag_skip = 1;
+       }
+    }
+
+  return 0;
+}
+
+
+static int
+mate3_and( tree_t * restrict ptree, int turn, int ply, int flag )
+{
+  unsigned int move;
+  char asq[2];
+
+  assert( InCheck(turn) );
+
+  ptree->anext_move[ply].next_phase = mate_king_cap_checker;
+  checker( ptree, asq, turn );
+
+  while ( gen_next_evasion_mate( ptree, asq, ply, turn, flag ) ) {
+
+    if ( ptree->anext_move[ply].next_phase == mate_intercept_drop_sup )
+      {
+       return 0;
+      }
+
+    MakeMove( turn, MOVE_CURR, ply );
+    assert( ! InCheck(turn) );
+
+    if ( InCheck( Flip(turn) ) ) { move = 0; }
+    else                         { move = IsMateIn1Ply( Flip(turn) ); }
+
+    if ( ! move
+        && ptree->anext_move[ply].next_phase == mate_intercept_weak_move )
+      {
+       assert( asq[1] == nsquare );
+       move = (unsigned int)mate_weak_or( ptree, Flip(turn), ply+1, asq[0],
+                                          I2To(MOVE_CURR) );
+      }
+
+    UnMakeMove( turn, MOVE_CURR, ply );
+      
+    if ( ! move ) { return 0; }
+  }
+  
+  return 1;
+}
+
+
+static int
+mate_weak_or( tree_t * restrict ptree, int turn, int ply, int from,
+             int to )
+{
+  int idirec, pc, pc_cap, value, flag;
+
+  if ( ply >= PLY_MAX-2 ) { return 0; }
+  
+  if ( turn )
+    {
+      if ( IsDiscoverWK( from, to ) ) { return 0; }
+
+      pc     = -BOARD[from];
+      pc_cap =  BOARD[to];
+      MOVE_CURR = ( To2Move(to) | From2Move(from)
+                     | Piece2Move(pc) | Cap2Move(pc_cap) );
+      if ( ( pc == bishop || pc == rook )
+          && ( to > I4 || from > I4 ) ) { MOVE_CURR |= FLAG_PROMO; }
+    }
+  else {
+    if ( IsDiscoverBK( from, to ) ) { return 0; }
+    
+    pc     =  BOARD[from];
+    pc_cap = -BOARD[to];
+    MOVE_CURR = ( To2Move(to) | From2Move(from) | Piece2Move(pc)
+                 | Cap2Move(pc_cap) );
+    if ( ( pc == bishop || pc == rook )
+        && ( to < A6 || from < A6 ) ) { MOVE_CURR |= FLAG_PROMO; }
+  }
+
+  MakeMove( turn, MOVE_CURR, ply );
+  if ( I2From(MOVE_LAST) < nsquare )
+    {
+      if ( InCheck(turn) )
+       {
+         UnMakeMove( turn, MOVE_CURR, ply );
+         return 0;
+       }
+      flag = 1;
+    }
+  else {
+    assert( ! InCheck(turn) );
+    flag = 2;
+  }
+  
+  ptree->move_last[ply] = ptree->move_last[ply-1];
+  value = mate3_and( ptree, Flip(turn), ply+1, flag );
+  
+  UnMakeMove( turn, MOVE_CURR, ply );
+
+  return value;
+}
+
+
+static int
+gen_next_evasion_mate( tree_t * restrict ptree, const char *psq, int ply,
+                      int turn, int flag )
+{
+  switch ( ptree->anext_move[ply].next_phase )
+    {
+    case mate_king_cap_checker:
+      ptree->anext_move[ply].next_phase = mate_cap_checker_gen;
+      MOVE_CURR = gen_king_cap_checker( ptree, psq[0], turn );
+      if ( MOVE_CURR ) { return 1; }
+
+    case mate_cap_checker_gen:
+      ptree->anext_move[ply].next_phase = mate_cap_checker;
+      ptree->anext_move[ply].move_last = ptree->move_last[ply-1];
+      ptree->move_last[ply]             = ptree->move_last[ply-1];
+      if ( psq[1] == nsquare )
+       {
+         ptree->move_last[ply]
+           = gen_move_to( ptree, psq[0], turn, ptree->move_last[ply-1] );
+       }
+
+    case mate_cap_checker:
+      if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+       {
+         MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+         return 1;
+       }
+
+    case mate_king_cap_gen:
+      ptree->anext_move[ply].next_phase = mate_king_cap;
+      ptree->anext_move[ply].move_last  = ptree->move_last[ply-1];
+      ptree->move_last[ply]
+       = gen_king_move( ptree, psq, turn, 1, ptree->move_last[ply-1] );
+
+    case mate_king_cap:
+      if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+       {
+         MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+         return 1;
+       }
+
+    case mate_king_move_gen:
+      ptree->anext_move[ply].next_phase = mate_king_move;
+      ptree->anext_move[ply].move_last  = ptree->move_last[ply-1];
+      ptree->move_last[ply]
+       = gen_king_move( ptree, psq, turn, 0, ptree->move_last[ply-1] );
+
+    case mate_king_move:
+      if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+       {
+         MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+         return 1;
+       }
+
+    case mate_intercept_move_gen:
+      ptree->anext_move[ply].remaining  = 0;
+      ptree->anext_move[ply].next_phase = mate_intercept_move;
+      ptree->anext_move[ply].move_last  = ptree->move_last[ply-1];
+      ptree->move_last[ply]             = ptree->move_last[ply-1];
+      if ( psq[1] == nsquare && abs(BOARD[(int)psq[0]]) != knight  )
+       {
+         int n;
+         ptree->move_last[ply] = gen_intercept( ptree, psq[0], ply, turn, &n,
+                                                ptree->move_last[ply-1],
+                                                flag );
+         if ( n < 0 )
+           {
+             ptree->anext_move[ply].next_phase = mate_intercept_drop_sup;
+             ptree->anext_move[ply].remaining  = 0;
+             MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+             return 1;
+           }
+
+         ptree->anext_move[ply].remaining = n;
+       }
+
+    case mate_intercept_move:
+      if ( ptree->anext_move[ply].remaining-- )
+       {
+         MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+         return 1;
+       }
+      ptree->anext_move[ply].next_phase = mate_intercept_weak_move;
+
+    case mate_intercept_weak_move:
+      if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+       {
+         MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+         return 1;
+       }
+      break;
+
+    default:
+      assert( 0 );
+    }
+
+  return 0;
+}
+
+
+static void
+checker( const tree_t * restrict ptree, char *psq, int turn )
+{
+  bitboard_t bb, bb_checkers;
+  int n, sq0, sq1, sq_king;
+
+  if ( turn )
+    {
+      sq_king     = SQ_WKING;
+      bb_checkers = BB_BOCCUPY;
+    }
+  else {
+    sq_king     = SQ_BKING;
+    bb_checkers = BB_WOCCUPY;
+  }
+  bb = attacks_to_piece( ptree, sq_king );
+  BBAnd( bb, bb, bb_checkers );
+
+  assert( BBToU(bb) );
+  sq0 = LastOne( bb );
+  sq1 = nsquare;
+
+  Xor( sq0, bb );
+  if ( BBToU( bb ) )
+    {
+      sq1 = LastOne( bb );
+      if ( BBContract( abb_king_attacks[sq_king], abb_mask[sq1] ) )
+       {
+         n   = sq0;
+         sq0 = sq1;
+         sq1 = n;
+       }
+    }
+
+  psq[0] = (char)sq0;
+  psq[1] = (char)sq1;
+}
+
+
+static unsigned int
+gen_king_cap_checker( const tree_t * restrict ptree, int to, int turn )
+{
+  unsigned int move;
+  int from;
+
+  if ( turn )
+    {
+      from = SQ_WKING;
+      if ( ! BBContract( abb_king_attacks[from],
+                        abb_mask[to] ) )   { return 0;}
+      if ( is_white_attacked( ptree, to ) ) { return 0; }
+      move = Cap2Move(BOARD[to]);
+    }
+  else {
+    from = SQ_BKING;
+    if ( ! BBContract( abb_king_attacks[from],
+                      abb_mask[to] ) )   { return 0;}
+    if ( is_black_attacked( ptree, to ) ) { return 0; }
+    move = Cap2Move(-BOARD[to]);
+  }
+  move |= To2Move(to) | From2Move(from) | Piece2Move(king);
+
+  return move;
+}
+
+
+static unsigned int *
+gen_move_to( const tree_t * restrict ptree, int to, int turn,
+            unsigned int * restrict pmove )
+{
+  bitboard_t bb;
+  int direc, from, pc, flag_promo, flag_unpromo;
+
+  bb = attacks_to_piece( ptree, to );
+  if ( turn )
+    {
+      BBAnd( bb, bb, BB_WOCCUPY );
+      BBNotAnd( bb, abb_mask[SQ_WKING] );
+      while ( BBToU(bb) )
+       {
+         from = LastOne( bb );
+         Xor( from, bb );
+
+         direc = (int)adirec[SQ_WKING][from];
+         if ( direc && is_pinned_on_white_king( ptree, from, direc ) )
+           {
+             continue;
+           }
+
+         flag_promo   = 0;
+         flag_unpromo = 1;
+         pc           = -BOARD[from];
+         switch ( pc )
+           {
+           case pawn:
+             if ( to > I4 ) { flag_promo = 1;  flag_unpromo = 0; }
+             break;
+
+           case lance:  case knight:
+             if      ( to > I3 ) { flag_promo = 1;  flag_unpromo = 0; }
+             else if ( to > I4 ) { flag_promo = 1; }
+             break;
+
+           case silver:
+             if ( to > I4 || from > I4 ) { flag_promo = 1; }
+             break;
+
+           case bishop:  case rook:
+             if ( to > I4
+                  || from > I4 ) { flag_promo = 1;  flag_unpromo = 0; }
+             break;
+
+           default:
+             break;
+           }
+         assert( flag_promo || flag_unpromo );
+         if ( flag_promo )
+           {
+             *pmove++ = ( From2Move(from) | To2Move(to) | FLAG_PROMO
+                          | Piece2Move(pc) | Cap2Move(BOARD[to]) );
+           }
+         if ( flag_unpromo )
+           {
+             *pmove++ = ( From2Move(from) | To2Move(to)
+                          | Piece2Move(pc) | Cap2Move(BOARD[to]) );
+           }
+       }
+    }
+  else {
+    BBAnd( bb, bb, BB_BOCCUPY );
+    BBNotAnd( bb, abb_mask[SQ_BKING] );
+    while ( BBToU(bb) )
+      {
+       from = FirstOne( bb );
+       Xor( from, bb );
+       
+       direc = (int)adirec[SQ_BKING][from];
+       if ( direc && is_pinned_on_black_king( ptree, from, direc ) )
+         {
+           continue;
+         }
+
+       flag_promo   = 0;
+       flag_unpromo = 1;
+       pc           = BOARD[from];
+       switch ( pc )
+         {
+         case pawn:
+           if ( to < A6 ) { flag_promo = 1;  flag_unpromo = 0; }
+           break;
+           
+         case lance:  case knight:
+           if      ( to < A7 ) { flag_promo = 1;  flag_unpromo = 0; }
+           else if ( to < A6 ) { flag_promo = 1; }
+           break;
+           
+         case silver:
+           if ( to < A6 || from < A6 ) { flag_promo = 1; }
+           break;
+           
+         case bishop:  case rook:
+           if ( to < A6
+                || from < A6 ) { flag_promo = 1;  flag_unpromo = 0; }
+           break;
+           
+         default:
+           break;
+         }
+       assert( flag_promo || flag_unpromo );
+       if ( flag_promo )
+         {
+           *pmove++ = ( From2Move(from) | To2Move(to) | FLAG_PROMO
+                        | Piece2Move(pc) | Cap2Move(-BOARD[to]) );
+         }
+       if ( flag_unpromo )
+         {
+           *pmove++ = ( From2Move(from) | To2Move(to)
+                        | Piece2Move(pc) | Cap2Move(-BOARD[to]) );
+         }
+      }
+  }
+
+  return pmove;
+}
+
+
+static unsigned int *
+gen_king_move( const tree_t * restrict ptree, const char *psq, int turn,
+              int is_capture, unsigned int * restrict pmove )
+{
+  bitboard_t bb;
+  int to, from;
+
+  if ( turn )
+    {
+      from = SQ_WKING;
+      bb      = abb_king_attacks[from];
+      if ( is_capture )
+       {
+         BBAnd( bb, bb, BB_BOCCUPY );
+         BBNotAnd( bb, abb_mask[(int)psq[0]] );
+       }
+      else { BBNotAnd( bb, BB_BOCCUPY ); }
+      BBNotAnd( bb, BB_WOCCUPY );
+    }
+  else {
+    from = SQ_BKING;
+    bb      = abb_king_attacks[from];
+    if ( is_capture )
+      {
+       BBAnd( bb, bb, BB_WOCCUPY );
+       BBNotAnd( bb, abb_mask[(int)psq[0]] );
+      }
+    else { BBNotAnd( bb, BB_WOCCUPY ); }
+    BBNotAnd( bb, BB_BOCCUPY );
+  }
+  
+  while ( BBToU(bb) )
+    {
+      to = LastOne( bb );
+      Xor( to, bb );
+
+      if ( psq[1] != nsquare
+          && ( adirec[from][(int)psq[1]]
+               == adirec[from][to] ) ) { continue; }
+
+      if ( psq[0] != to
+          && adirec[from][(int)psq[0]] == adirec[from][to] ) {
+         if ( adirec[from][(int)psq[0]] & flag_cross )
+           {
+             if ( abs(BOARD[(int)psq[0]]) == lance
+                  || abs(BOARD[(int)psq[0]]) == rook
+                  || abs(BOARD[(int)psq[0]]) == dragon ) { continue; }
+           }
+         else if ( ( adirec[from][(int)psq[0]] & flag_diag )
+                   && ( abs(BOARD[(int)psq[0]]) == bishop
+                        || abs(BOARD[(int)psq[0]]) == horse ) ){ continue; }
+       }
+
+      if ( turn )
+       {
+         if ( is_white_attacked( ptree, to ) ) { continue; }
+
+         *pmove++ = ( From2Move(from) | To2Move(to)
+                      | Piece2Move(king) | Cap2Move(BOARD[to]) );
+       }
+      else {
+       if ( is_black_attacked( ptree, to ) ) { continue; }
+
+       *pmove++ = ( From2Move(from) | To2Move(to)
+                    | Piece2Move(king) | Cap2Move(-BOARD[to]) );
+      }
+    }
+
+  return pmove;
+}
+
+
+static unsigned int *
+gen_intercept( tree_t * restrict __ptree__, int sq_checker, int ply, int turn,
+              int * restrict premaining, unsigned int * restrict pmove,
+              int flag )
+{
+#define Drop(pc) ( To2Move(to) | Drop2Move(pc) )
+
+  const tree_t * restrict ptree = __ptree__;
+  bitboard_t bb_atk, bb_defender, bb;
+  unsigned int amove[16];
+  unsigned int hand;
+  int n0, n1, inc, pc, sq_k, to, from, direc, nmove, nsup, i, min_chuai, itemp;
+  int dist, flag_promo, flag_unpromo;
+
+  n0 = n1 = 0;
+  if ( turn )
+    {
+      sq_k        = SQ_WKING;
+      bb_defender = BB_WOCCUPY;
+      BBNotAnd( bb_defender, abb_mask[sq_k] );
+    }
+  else {
+    sq_k        = SQ_BKING;
+    bb_defender = BB_BOCCUPY;
+    BBNotAnd( bb_defender, abb_mask[sq_k] );
+  }
+
+  switch ( adirec[sq_k][sq_checker] )
+    {
+    case direc_rank:
+      min_chuai = ( sq_k < A8 || I2 < sq_k ) ? 2 : 4;
+      inc       = 1;
+      break;
+
+    case direc_diag1:
+      min_chuai = 3;
+      inc       = 8;
+      break;
+
+    case direc_file:
+      itemp     = (int)aifile[sq_k];
+      min_chuai = ( itemp == file1 || itemp == file9 ) ? 2 : 4;
+      inc = 9;
+      break;
+
+    default:
+      assert( (int)adirec[sq_k][sq_checker] == direc_diag2 );
+      min_chuai = 3;
+      inc       = 10;
+    }
+  if ( sq_k > sq_checker ) { inc = -inc; }
+  
+  for ( dist = 1, to = sq_k + inc;
+       to != sq_checker;
+       dist += 1, to += inc ) {
+
+    assert( 0 <= to && to < nsquare && BOARD[to] == empty );
+
+    nmove  = 0;
+    bb_atk = attacks_to_piece( ptree, to );
+    BBAnd( bb, bb_defender, bb_atk );
+    while ( BBToU(bb) )
+      {
+       from = LastOne( bb );
+       Xor( from, bb );
+       
+       direc        = (int)adirec[sq_k][from];
+       flag_promo   = 0;
+       flag_unpromo = 1;
+       if ( turn )
+         {
+           if ( direc && is_pinned_on_white_king( ptree, from, direc ) )
+             {
+               continue;
+             }
+           pc = -BOARD[from];
+           switch ( pc )
+             {
+             case pawn:
+               if ( to > I4 ) { flag_promo = 1;  flag_unpromo = 0; }
+               break;
+               
+             case lance:  case knight:
+               if      ( to > I3 ) { flag_promo = 1;  flag_unpromo = 0; }
+               else if ( to > I4 ) { flag_promo = 1; }
+               break;
+               
+             case silver:
+               if ( to > I4 || from > I4 ) { flag_promo = 1; }
+               break;
+               
+             case bishop:  case rook:
+               if ( to > I4
+                    || from > I4 ) { flag_promo = 1;  flag_unpromo = 0; }
+               break;
+               
+             default:
+               break;
+             }
+         }
+       else {
+         if ( direc && is_pinned_on_black_king( ptree, from, direc ) )
+           {
+             continue;
+           }
+         pc = BOARD[from];
+         switch ( pc )
+           {
+           case pawn:
+             if ( to < A6 ) { flag_promo = 1;  flag_unpromo = 0; }
+             break;
+             
+           case lance:  case knight:
+             if      ( to < A7 ) { flag_promo = 1;  flag_unpromo = 0; }
+             else if ( to < A6 ) { flag_promo = 1; }
+             break;
+             
+           case silver:
+             if ( to < A6 || from < A6 ) { flag_promo = 1; }
+             break;
+             
+           case bishop:  case rook:
+             if ( to < A6
+                  || from < A6 ) { flag_promo = 1;  flag_unpromo = 0; }
+             break;
+             
+           default:
+             break;
+           }
+       }
+       assert( flag_promo || flag_unpromo );
+       if ( flag_promo )
+         {
+           amove[nmove++] = ( From2Move(from) | To2Move(to)
+                              | FLAG_PROMO | Piece2Move(pc) );
+         }
+       if ( flag_unpromo )
+         {
+           amove[nmove++] = ( From2Move(from) | To2Move(to)
+                              | Piece2Move(pc) );
+         }
+      }
+    
+    nsup = ( to == sq_k + inc ) ? nmove + 1 : nmove;
+    if ( nsup > 1 )
+      {
+       for ( i = n0 + n1 - 1; i >= n0; i-- ) { pmove[i+nmove] = pmove[i]; }
+       for ( i = 0; i < nmove; i++ ) { pmove[n0++] = amove[i]; }
+      }
+    else if ( nmove ) { pmove[n0 + n1++] = amove[0]; }
+    
+    if ( ! nsup )
+      {
+       /* - tentative assumption - */
+       /* no recursive drops at non-supported square. */
+       if ( flag == 2  ) { continue; }
+       
+       /* -tentative assumption- */
+       /* no intercept-drop at non-supported square. */
+       if ( I2To(MOVE_LAST) == sq_checker && dist > min_chuai ) { continue; }
+      }
+    
+    nmove = 0;
+    
+    if ( turn ) {
+      
+      hand = HAND_W;
+      
+      if ( nsup ) {
+       
+       if ( IsHandRook(hand) ) { amove[nmove++] = Drop(rook); }
+       else if ( IsHandLance(hand) && to < A1 )
+         {
+           amove[nmove++] = Drop(lance);
+         }
+       else if ( IsHandPawn(hand)
+                 && to < A1
+                 && ! ( BBToU(BB_WPAWN) & ( mask_file1 >> aifile[to] ) )
+                 && ! IsMateWPawnDrop( __ptree__, to ) )
+         {
+           amove[nmove++] = Drop(pawn);
+         }
+       
+      } else {
+       
+       if ( IsHandPawn(hand)
+            && to < A1
+            && ! ( BBToU(BB_WPAWN) & ( mask_file1 >> aifile[to] ) )
+            && ! IsMateWPawnDrop( __ptree__, to ) )
+         {
+           amove[nmove++] = Drop(pawn);
+         }
+       if ( IsHandLance(hand) && to < A1 ) { amove[nmove++] = Drop(lance); }
+       if ( IsHandRook(hand) )             { amove[nmove++] = Drop(rook); }
+      }
+      
+      if ( IsHandKnight(hand) && to < A2 ) { amove[nmove++] = Drop(knight); }
+      
+    } else {
+      
+      hand = HAND_B;
+      
+      if ( nsup ) {
+       
+       if ( IsHandRook(hand) ) { amove[nmove++] = Drop(rook); }
+       else if ( IsHandLance(hand) && to > I9 )
+         {
+           amove[nmove++] = Drop(lance);
+         }
+       else if ( IsHandPawn(hand)
+                 && to > I9
+                 && ! ( BBToU(BB_BPAWN) & ( mask_file1 >> aifile[to] ) )
+                 && ! IsMateBPawnDrop( __ptree__, to ) )
+         {
+           amove[nmove++] = Drop(pawn);
+         }
+       
+      } else {
+       
+       if ( IsHandPawn(hand)
+            && to > I9
+            && ! ( BBToU(BB_BPAWN) & ( mask_file1 >> aifile[to] ) )
+            && ! IsMateBPawnDrop( __ptree__, to ) )
+         {
+           amove[nmove++] = Drop(pawn);
+         }
+       if ( IsHandLance(hand) && to > I9 ) { amove[nmove++] = Drop(lance); }
+       if ( IsHandRook(hand) )             { amove[nmove++] = Drop(rook); }
+      }
+      
+      if ( IsHandKnight(hand) && to > I8 ) { amove[nmove++] = Drop(knight); }
+    }
+    
+    if ( IsHandSilver(hand) ) { amove[nmove++] = Drop(silver); }
+    if ( IsHandGold(hand) )   { amove[nmove++] = Drop(gold); }
+    if ( IsHandBishop(hand) ) { amove[nmove++] = Drop(bishop); }
+    
+    if ( nsup )
+      {
+       /* - tentative assumption - */
+       /* a supported intercepter saves the king for two plies at least. */
+       if ( nmove && flag == 0 && dist > min_chuai
+            && I2From(MOVE_LAST) >= nsquare )
+           {
+             *premaining = -1;
+             pmove[0]    = amove[0];
+             return pmove + 1;
+           }
+
+       for ( i = n0 + n1 - 1; i >= n0; i-- ) { pmove[i+nmove] = pmove[i]; }
+       for ( i = 0; i < nmove; i++ ) { pmove[n0++] = amove[i]; }
+      }
+    else for ( i = 0; i < nmove; i++ ) { pmove[n0 + n1++] = amove[i]; }
+  }
+  
+  *premaining = n0;
+  return pmove + n0 + n1;
+
+#undef Drop
+}
diff --git a/movgenex.c b/movgenex.c
new file mode 100644 (file)
index 0000000..f21d240
--- /dev/null
@@ -0,0 +1,415 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+
+#define BAddMoveCap(piece)                                             \
+            utemp = From2Move(from) | Piece2Move(piece);               \
+            while ( BBToU( bb_move ) ) {                               \
+             to       = LastOne( bb_move );                           \
+             *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp;   \
+             Xor( to, bb_move ); }
+
+#define BAddMove(piece) utemp = From2Move(from) | Piece2Move(piece); \
+                        while ( BBToU( bb_move ) ) {                 \
+                        to       = LastOne( bb_move );               \
+                        *pmove++ = To2Move(to) | utemp;              \
+                       Xor( to, bb_move ); }
+
+
+#define WAddMoveCap(piece)                                            \
+            utemp = From2Move(from) | Piece2Move(piece);              \
+            while ( BBToU( bb_move ) ) {                              \
+             to      = FirstOne( bb_move );                          \
+             *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp;   \
+             Xor( to, bb_move ); }
+
+#define WAddMove(piece) utemp = From2Move(from) | Piece2Move(piece);  \
+                         while ( BBToU( bb_move ) ) {                 \
+                          to       = FirstOne( bb_move );            \
+                          *pmove++ = To2Move(to) | utemp;            \
+                          Xor( to, bb_move ); }
+
+
+unsigned int *
+b_gen_cap_nopro_ex2( const tree_t * restrict ptree,
+                    unsigned int * restrict pmove )
+{
+  int from, to;
+  unsigned int utemp, ubb_piece0, ubb_piece1, ubb_piece2, ubb_move0;
+  bitboard_t bb_target, bb_move, bb_piece;
+
+  bb_target = BB_WOCCUPY;
+
+  ubb_move0 = BB_BPAWN_ATK.p[0] & bb_target.p[0] & 0x003ffffU;
+  while( ubb_move0 )
+    {
+      to   = last_one0( ubb_move0 );
+      from = to + 9;
+      *pmove++ = To2Move(to) | From2Move(from)
+       | Cap2Move(-BOARD[to]) | Piece2Move(pawn);
+      ubb_move0 ^= abb_mask[to].p[0];
+    }
+
+  ubb_piece1 = BB_BBISHOP.p[1];
+  ubb_piece2 = BB_BBISHOP.p[2];
+  while( ubb_piece1 | ubb_piece2 )
+    {
+      from     = last_one12( ubb_piece1, ubb_piece2 );
+      ubb_move0 = BishopAttack0(from) & bb_target.p[0];
+      utemp     = From2Move(from) | Piece2Move(bishop);
+      while ( ubb_move0 )
+       {
+         to      = last_one0( ubb_move0 );
+         *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp;
+         ubb_move0 ^= abb_mask[to].p[0];
+       }
+      ubb_piece1 ^= abb_mask[from].p[1];
+      ubb_piece2 ^= abb_mask[from].p[2];
+    }
+  ubb_piece0 = BB_BBISHOP.p[0];
+  while( ubb_piece0 )
+    {
+      from = last_one0( ubb_piece0 );
+      AttackBishop( bb_move, from );
+      BBAnd( bb_move, bb_move, bb_target );
+      BAddMoveCap( bishop );
+      ubb_piece0 ^= abb_mask[from].p[0];
+    }
+
+  ubb_piece1 = BB_BROOK.p[1];
+  ubb_piece2 = BB_BROOK.p[2];
+  while( ubb_piece1 | ubb_piece2 )
+    {
+      from     = last_one12( ubb_piece1, ubb_piece2 );
+      AttackRook( bb_move, from );
+      ubb_move0 = bb_move.p[0] & bb_target.p[0];
+      utemp = From2Move(from) | Piece2Move(rook);
+      while ( ubb_move0 )
+       {
+         to      = last_one0( ubb_move0 );
+         *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp;
+         ubb_move0 ^= abb_mask[to].p[0];
+       }
+      ubb_piece1 ^= abb_mask[from].p[1];
+      ubb_piece2 ^= abb_mask[from].p[2];
+    }
+  ubb_piece0 = BB_BROOK.p[0];
+  while( ubb_piece0 )
+    {
+      from     = last_one0( ubb_piece0 );
+      AttackRook( bb_move, from );
+      BBAnd( bb_move, bb_move, bb_target );
+      BAddMoveCap( rook );
+      ubb_piece0 ^= abb_mask[from].p[0];
+    }
+
+  bb_piece = BB_BLANCE;
+  bb_target.p[0] &= 0x3fe00;
+  while( BBToU( bb_piece ) )
+    {
+      from     = LastOne( bb_piece );
+      ubb_move0 = AttackFile(from).p[0]
+       & abb_minus_rays[from].p[0] & bb_target.p[0];
+      utemp = From2Move(from) | Piece2Move(lance);
+      while ( ubb_move0 )
+       {
+         to      = last_one0( ubb_move0 );
+         *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp;
+         ubb_move0 ^= abb_mask[to].p[0];
+       }
+      Xor( from, bb_piece );
+    }
+
+  return pmove;
+}
+
+
+unsigned int *
+b_gen_nocap_nopro_ex2( const tree_t * restrict ptree,
+                      unsigned int * restrict pmove )
+{
+  bitboard_t bb_target, bb_move, bb_piece;
+  unsigned int ubb_piece0, ubb_piece1, ubb_piece2, ubb_move0, ubb_target0;
+  unsigned int utemp;
+  int to, from;
+
+  BBOr( bb_target, BB_BOCCUPY, BB_WOCCUPY );
+  BBNot( bb_target, bb_target );
+
+  ubb_move0 = BB_BPAWN_ATK.p[0] & bb_target.p[0] & 0x003ffffU;
+  while( ubb_move0 )
+    {
+      to   = last_one0( ubb_move0 );
+      from = to + 9;
+      *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(pawn);
+      ubb_move0 ^= abb_mask[to].p[0];
+    }
+
+  ubb_piece1 = BB_BBISHOP.p[1];
+  ubb_piece2 = BB_BBISHOP.p[2];
+  while( ubb_piece1 | ubb_piece2 )
+    {
+      from     = last_one12( ubb_piece1, ubb_piece2 );
+      ubb_move0 = BishopAttack0(from) & bb_target.p[0];
+      utemp     = From2Move(from) | Piece2Move(bishop);
+      while ( ubb_move0 )
+       {
+         to      = last_one0( ubb_move0 );
+         *pmove++ = To2Move(to) | utemp;
+         ubb_move0 ^= abb_mask[to].p[0];
+       }
+      ubb_piece1 ^= abb_mask[from].p[1];
+      ubb_piece2 ^= abb_mask[from].p[2];
+    }
+  ubb_piece0 = BB_BBISHOP.p[0];
+  while( ubb_piece0 )
+    {
+      from = last_one0( ubb_piece0 );
+      AttackBishop( bb_move, from );
+      BBAnd( bb_move, bb_move, bb_target );
+      BAddMove( bishop );
+      ubb_piece0 ^= abb_mask[from].p[0];
+    }
+
+  ubb_piece1 = BB_BROOK.p[1];
+  ubb_piece2 = BB_BROOK.p[2];
+  while( ubb_piece1 | ubb_piece2 )
+    {
+      from     = last_one12( ubb_piece1, ubb_piece2 );
+      AttackRook( bb_move, from );
+      ubb_move0 = bb_move.p[0] & bb_target.p[0];
+      utemp = From2Move(from) | Piece2Move(rook);
+      while ( ubb_move0 )
+       {
+         to      = last_one0( ubb_move0 );
+         *pmove++ = To2Move(to) | utemp;
+         ubb_move0 ^= abb_mask[to].p[0];
+       }
+      ubb_piece1 ^= abb_mask[from].p[1];
+      ubb_piece2 ^= abb_mask[from].p[2];
+    }
+  ubb_piece0 = BB_BROOK.p[0];
+  while( ubb_piece0 )
+    {
+      from     = last_one0( ubb_piece0 );
+      AttackRook( bb_move, from );
+      BBAnd( bb_move, bb_move, bb_target );
+      BAddMove( rook );
+      ubb_piece0 ^= abb_mask[from].p[0];
+    }
+
+  bb_piece = BB_BLANCE;
+  ubb_target0 = bb_target.p[0] & 0x3fe00;
+  while( BBToU( bb_piece ) )
+    {
+      from     = LastOne( bb_piece );
+      ubb_move0 = AttackFile(from).p[0]
+       & abb_minus_rays[from].p[0] & ubb_target0;
+      utemp = From2Move(from) | Piece2Move(lance);
+      while ( ubb_move0 )
+       {
+         to = last_one0( ubb_move0 );
+         *pmove++ = To2Move(to) | utemp;
+         ubb_move0 ^= abb_mask[to].p[0];
+       }
+      Xor( from, bb_piece );
+    }
+
+  return pmove;
+}
+
+
+unsigned int *
+w_gen_cap_nopro_ex2( const tree_t * restrict ptree,
+                    unsigned int * restrict pmove )
+{
+  bitboard_t bb_target, bb_move, bb_piece;
+  unsigned int utemp, ubb_piece0, ubb_piece1, ubb_piece2, ubb_move2;
+  int from, to;
+
+  bb_target = BB_BOCCUPY;
+
+  ubb_move2 = BB_WPAWN_ATK.p[2] & bb_target.p[2] & 0x7fffe00U;
+  while( ubb_move2 )
+    {
+      to   = first_one2( ubb_move2 );
+      from = to - 9;
+      *pmove++ = To2Move(to) | From2Move(from)
+       | Cap2Move(BOARD[to]) | Piece2Move(pawn);
+      ubb_move2 ^= abb_mask[to].p[2];
+    }
+
+  ubb_piece0 = BB_WBISHOP.p[0];
+  ubb_piece1 = BB_WBISHOP.p[1];
+  while( ubb_piece0 | ubb_piece1 )
+    {
+      from     = first_one01( ubb_piece0, ubb_piece1 );
+      ubb_move2 = BishopAttack2(from) & bb_target.p[2];
+      utemp     = From2Move(from) | Piece2Move(bishop);
+      while ( ubb_move2 )
+       {
+         to      = first_one2( ubb_move2 );
+         *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp;
+         ubb_move2 ^= abb_mask[to].p[2];
+       }
+      ubb_piece0 ^= abb_mask[from].p[0];
+      ubb_piece1 ^= abb_mask[from].p[1];
+    }
+  ubb_piece2 = BB_WBISHOP.p[2];
+  while( ubb_piece2 )
+    {
+      from = first_one2( ubb_piece2 );
+      AttackBishop( bb_move, from );
+      BBAnd( bb_move, bb_move, bb_target );
+      WAddMoveCap( bishop );
+      ubb_piece2 ^= abb_mask[from].p[2];
+    }
+
+  ubb_piece0 = BB_WROOK.p[0];
+  ubb_piece1 = BB_WROOK.p[1];
+  while( ubb_piece0 | ubb_piece1 )
+    {
+      from     = first_one01( ubb_piece0, ubb_piece1 );
+      AttackRook( bb_move, from );
+      ubb_move2 = bb_move.p[2] & bb_target.p[2];
+      utemp     = From2Move(from) | Piece2Move(rook);
+      while ( ubb_move2 )
+       {
+         to      = first_one2( ubb_move2 );
+         *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp;
+         ubb_move2 ^= abb_mask[to].p[2];
+       }
+      ubb_piece0 ^= abb_mask[from].p[0];
+      ubb_piece1 ^= abb_mask[from].p[1];
+    }
+  ubb_piece2 = BB_WROOK.p[2];
+  while( ubb_piece2 )
+    {
+      from     = first_one2( ubb_piece2 );
+      AttackRook( bb_move, from );
+      BBAnd( bb_move, bb_move, bb_target );
+      WAddMoveCap( rook );
+      ubb_piece2 ^= abb_mask[from].p[2];
+    }
+
+  bb_piece = BB_WLANCE;
+  bb_target.p[2] &= 0x3fe00;
+  while( BBToU( bb_piece ) )
+    {
+      from      = FirstOne( bb_piece );
+      ubb_move2 = AttackFile(from).p[2]
+       & abb_plus_rays[from].p[2] & bb_target.p[2];
+      utemp = From2Move(from) | Piece2Move(lance);
+      while ( ubb_move2 )
+       {
+         to       = first_one2( ubb_move2 );
+         *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp;
+         ubb_move2 ^= abb_mask[to].p[2];
+       }
+      Xor( from, bb_piece );
+    }
+
+  return pmove;
+}
+
+
+unsigned int *
+w_gen_nocap_nopro_ex2( const tree_t * restrict ptree,
+                      unsigned int * restrict pmove )
+{
+  bitboard_t bb_target, bb_piece, bb_move;
+  unsigned int ubb_piece0, ubb_piece1, ubb_piece2, ubb_move2, ubb_target2;
+  unsigned int utemp;
+  int to, from;
+
+  BBOr( bb_target, BB_BOCCUPY, BB_WOCCUPY );
+  BBNot( bb_target, bb_target );
+
+  ubb_move2 = BB_WPAWN_ATK.p[2] & bb_target.p[2] & 0x7fffe00U;;
+  while( ubb_move2 )
+    {
+      to   = first_one2( ubb_move2 );
+      from = to - 9;
+      *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(pawn);
+      ubb_move2 ^= abb_mask[to].p[2];
+    }
+
+  ubb_piece0 = BB_WBISHOP.p[0];
+  ubb_piece1 = BB_WBISHOP.p[1];
+  while( ubb_piece0 | ubb_piece1 )
+    {
+      from     = first_one01( ubb_piece0, ubb_piece1 );
+      ubb_move2 = BishopAttack2(from) & bb_target.p[2];
+      utemp     = From2Move(from) | Piece2Move(bishop);
+      while ( ubb_move2 )
+       {
+         to      = first_one2( ubb_move2 );
+         *pmove++ = To2Move(to) | utemp;
+         ubb_move2 ^= abb_mask[to].p[2];
+       }
+      ubb_piece0 ^= abb_mask[from].p[0];
+      ubb_piece1 ^= abb_mask[from].p[1];
+    }
+  ubb_piece2 = BB_WBISHOP.p[2];
+  while( ubb_piece2 )
+    {
+      from = first_one2( ubb_piece2 );
+      AttackBishop( bb_move, from );
+      BBAnd( bb_move, bb_move, bb_target );
+      WAddMove( bishop );
+      ubb_piece2 ^= abb_mask[from].p[2];
+    }
+
+  ubb_piece0 = BB_WROOK.p[0];
+  ubb_piece1 = BB_WROOK.p[1];
+  while( ubb_piece0 | ubb_piece1 )
+    {
+      from      = first_one01( ubb_piece0, ubb_piece1 );
+      AttackRook( bb_move, from );
+      ubb_move2 = bb_move.p[2] & bb_target.p[2];
+      utemp     = From2Move(from) | Piece2Move(rook);
+      while ( ubb_move2 )
+       {
+         to       = first_one2( ubb_move2 );
+         *pmove++ = To2Move(to) | utemp;
+         ubb_move2 ^= abb_mask[to].p[2];
+       }
+      ubb_piece0 ^= abb_mask[from].p[0];
+      ubb_piece1 ^= abb_mask[from].p[1];
+    }
+  ubb_piece2 = BB_WROOK.p[2];
+  while( ubb_piece2 )
+    {
+      from     = first_one2( ubb_piece2 );
+      AttackRook( bb_move, from );
+      BBAnd( bb_move, bb_move, bb_target );
+      WAddMove( rook );
+      ubb_piece2 ^= abb_mask[from].p[2];
+    }
+
+  bb_piece = BB_WLANCE;
+  ubb_target2 = bb_target.p[2] & 0x3fe00;
+  while( BBToU( bb_piece ) )
+    {
+      from = FirstOne( bb_piece );
+      ubb_move2 = AttackFile(from).p[2]
+       & abb_plus_rays[from].p[2] & ubb_target2;
+      utemp = From2Move(from) | Piece2Move(lance);
+      while ( ubb_move2 )
+       {
+         to = first_one2( ubb_move2 );
+         *pmove++ = To2Move(to) | utemp;
+         ubb_move2 ^= abb_mask[to].p[2];
+       }
+      Xor( from, bb_piece );
+    }
+
+  return pmove;
+}
+
+
+#undef BAddMoveCap
+#undef BAddMove
+#undef WAddMoveCap
+#undef WAddMove
diff --git a/next.c b/next.c
new file mode 100644 (file)
index 0000000..f0153ac
--- /dev/null
+++ b/next.c
@@ -0,0 +1,355 @@
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include "shogi.h"
+
+int
+gen_next_move( tree_t * restrict ptree, int ply, int turn )
+{
+  switch ( ptree->anext_move[ply].next_phase )
+    {
+    case next_move_hash:
+      {
+       unsigned int * restrict pmove;
+       int * restrict psortv = ptree->sort_value;
+       unsigned int move, killer1, killer2, move_hash, move_best, move_second;
+       int i, j, sortv, n, value_best, value_second, value, remaining;
+
+       ptree->anext_move[ply].phase_done = 0;
+       ptree->anext_move[ply].next_phase = next_move_capture;
+       ptree->anext_move[ply].move_last  = pmove = ptree->move_last[ply];
+       ptree->move_last[ply] = GenCaptures( turn, pmove );
+
+       move_hash  = ptree->amove_hash[ply];
+       killer1    = ptree->amove_killer[ply].no1;
+       killer2    = ptree->amove_killer[ply].no2;
+       remaining  = 0;
+       move_best  = move_second  = 0;
+       value_best = value_second = 0;
+       n = (int)( ptree->move_last[ply] - pmove );
+       for ( i = 0; i < n; i++ )
+         {
+           move = pmove[i];
+           sortv = swap( ptree, move, -1, INT_MAX, turn );
+           if ( sortv > value_best )
+             {
+               move_second  = move_best;
+               value_second = value_best;
+               value_best = sortv;
+               move_best  = move;
+             }
+           else if ( sortv > value_second )
+             {
+               move_second  = move;
+               value_second = sortv;
+             }
+           if ( move == move_hash ) { sortv = INT_MIN; }
+           else if ( UToFromToPromo(move) == killer1 )
+             {
+               killer1 = 0;
+               value = ptree->amove_killer[ply].no1_value
+                 + p_value_ex[15U+UToCap(move)];
+               if ( sortv < value ) { sortv = value; }
+               if ( sortv > -1 ) { remaining++; }
+             }
+           else if ( UToFromToPromo(move) == killer2 )
+             {
+               killer2 = 0;
+               value = ptree->amove_killer[ply].no2_value
+                 + p_value_ex[15U+UToCap(move)];
+               if ( sortv < value ) { sortv = value; }
+               if ( sortv > -1 ) { remaining++; }
+             }
+           else if ( sortv > -1 ) { remaining++; }
+           psortv[i] = sortv;
+         }
+
+       if ( killer1
+            && killer1 != move_hash
+            && ptree->amove_killer[ply].no1_value > -1
+            && is_move_valid( ptree, killer1, turn ) )
+         {
+           *( ptree->move_last[ply]++ ) = killer1;
+           psortv[n++] = ptree->amove_killer[ply].no1_value;
+           remaining++;
+         }
+
+       if ( killer2
+            && killer2 != move_hash
+            && ptree->amove_killer[ply].no2_value > -1
+            && is_move_valid( ptree, killer2, turn ) )
+         {
+           *( ptree->move_last[ply]++ ) = killer2;
+           psortv[n++] = ptree->amove_killer[ply].no2_value;
+           remaining++;
+         }
+
+       ptree->anext_move[ply].value_cap1 = value_best;
+       ptree->anext_move[ply].move_cap1  = move_best;
+       ptree->anext_move[ply].value_cap2 = value_second;
+       ptree->anext_move[ply].move_cap2  = move_second;
+       ptree->anext_move[ply].remaining  = remaining;
+
+       /* insertion sort */
+       psortv[n] = INT_MIN;
+       for ( i = n-2; i >= 0; i-- )
+         {
+           sortv = psortv[i];  move = pmove[i];
+           for ( j = i+1; psortv[j] > sortv; j++ )
+             {
+               psortv[j-1] = psortv[j];  pmove[j-1] = pmove[j];
+             }
+           psortv[j-1] = sortv;  pmove[j-1] = move;
+         }
+       if ( psortv[n-1] == INT_MIN ) { ptree->move_last[ply]--; }
+
+#if ! defined(MINIMUM)
+       if ( move_hash && ! is_move_valid( ptree, move_hash, turn ) )
+         {
+           out_warning( "An invalid hash move is found!!" );
+           ptree->amove_hash[ply] = move_hash = 0U;
+         }
+#endif
+
+       if ( move_hash )
+         {
+           if ( move_hash == move_best )
+             {
+               ptree->anext_move[ply].phase_done |= phase_cap1;
+             }
+
+           if ( UToFromToPromo(move_hash) == killer1 )
+             {
+               ptree->anext_move[ply].phase_done |= phase_killer1;
+             }
+           else if ( UToFromToPromo(move_hash) == killer2 )
+             { 
+               ptree->anext_move[ply].phase_done |= phase_killer2;
+             }
+           ptree->anext_move[ply].phase_done |= phase_hash;
+           MOVE_CURR = move_hash;
+           return 1;
+         }
+      }
+      
+    case next_move_capture:
+      if ( ptree->anext_move[ply].remaining-- )
+       {
+         unsigned int move;
+
+         MOVE_CURR = move = *(ptree->anext_move[ply].move_last++);
+         if ( move == ptree->anext_move[ply].move_cap1 )
+           {
+             ptree->anext_move[ply].phase_done |= phase_cap1;
+           }
+
+         if ( UToFromToPromo(move) == ptree->amove_killer[ply].no1 )
+           {
+             ptree->anext_move[ply].phase_done |= phase_killer1;
+           }
+         else if ( UToFromToPromo(move) == ptree->amove_killer[ply].no2 )
+           { 
+             ptree->anext_move[ply].phase_done |= phase_killer2;
+           }
+         return 1;
+       }
+
+      {
+       unsigned int * restrict pmove;
+       unsigned int value_best, value, key, good, tried;
+       int i, n, ibest;
+
+       value_best =  0;
+       ibest      = -1;
+       ptree->move_last[ply] = GenNoCaptures( turn, ptree->move_last[ply] );
+       ptree->move_last[ply] = GenDrop( turn, ptree->move_last[ply] );
+       n = (int)( ptree->move_last[ply] - ptree->anext_move[ply].move_last );
+       pmove = ptree->anext_move[ply].move_last;
+       for ( i = 0; i < n; i++ )
+         {
+           if ( pmove[i] == ptree->amove_hash[ply]
+                || ( pmove[i] == ptree->amove_killer[ply].no1
+                     && ( ptree->anext_move[ply].phase_done
+                          & phase_killer1 ) )
+                || ( pmove[i] == ptree->amove_killer[ply].no2
+                     && ( ptree->anext_move[ply].phase_done
+                          & phase_killer2 ) ) )
+             {
+               pmove[i] = 0;
+               continue;
+             }
+
+           if ( UToCap(pmove[i]) ) { continue; }
+           if ( I2IsPromote(pmove[i])
+                && I2PieceMove(pmove[i]) != silver ) { continue; }
+
+
+           key   = phash( pmove[i], turn );
+           good  = ptree->hist_good[key]  + 1;
+           tried = ptree->hist_tried[key] + 2;
+           value = ( good * 8192U ) / tried;
+           if ( value > value_best )
+             {
+               value_best = value;
+               ibest      = i;
+             }
+         }
+
+       if ( ibest >= 0 )
+         {
+           ptree->anext_move[ply].phase_done |= phase_history1;
+           ptree->anext_move[ply].next_phase  = next_move_history2;
+           MOVE_CURR  = pmove[ibest];
+           pmove[ibest] = 0;
+           return 1;
+         }
+      }
+      
+    case next_move_history2:
+      {
+       unsigned int * restrict pmove;
+       unsigned int value_best, value, key, good, tried;
+       int ibest, i, n;
+
+       ptree->anext_move[ply].next_phase = next_move_misc;
+       value_best = 0;
+       ibest      = -1;
+       n = (int)( ptree->move_last[ply] - ptree->anext_move[ply].move_last );
+       pmove = ptree->anext_move[ply].move_last;
+
+       for ( i = 0; i < n; i++ )
+         {
+           if ( UToCap(pmove[i]) ) { continue; }
+           if ( I2IsPromote(pmove[i])
+                && I2PieceMove(pmove[i]) != silver ) { continue; }
+
+           key   = phash( pmove[i], turn );
+           good  = ptree->hist_good[key]  + 1;
+           tried = ptree->hist_tried[key] + 2;
+           value = ( good * 8192U ) / tried;
+           if ( value > value_best && pmove[i] )
+             {
+               value_best = value;
+               ibest      = i;
+             }
+         }
+
+       if ( ibest >= 0 )
+         {
+           ptree->anext_move[ply].phase_done |= phase_history2;
+           MOVE_CURR  = pmove[ibest];
+           pmove[ibest] = 0;
+           return 1;
+         }
+      }
+      
+    default:
+      assert( ptree->anext_move[ply].next_phase == next_move_misc );
+      while ( ptree->anext_move[ply].move_last < ptree->move_last[ply] )
+       {
+         if ( *( ptree->anext_move[ply].move_last ) )
+           {
+             MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+             ptree->anext_move[ply].phase_done |= phase_misc;
+             return 1;
+           }
+         ptree->anext_move[ply].move_last++;
+       }
+    }
+  return 0;
+}
+
+
+int
+gen_next_evasion( tree_t * restrict ptree, int ply, int turn )
+{
+  switch ( ptree->anext_move[ply].next_phase )
+    {
+    case next_evasion_hash:
+      ptree->move_last[ply] = GenEvasion( turn, ptree->move_last[ply] );
+
+      if ( ptree->amove_hash[ply] )
+       {
+#if ! defined(MINIMUM)
+         unsigned int * restrict p;
+         
+         for ( p = ptree->move_last[ply-1]; p < ptree->move_last[ply]; p++ )
+           if ( *p == ptree->amove_hash[ply] ) { break; }
+         
+         if ( *p != ptree->amove_hash[ply] )
+           {
+             out_warning( "An invalid hash evasion-move is found!!" );
+             out_board( ptree, stdout, 0, 0 );
+             Out( "%c%s\n", ach_turn[turn],
+                  str_CSA_move(ptree->amove_hash[ply]) );
+             Out( "hash key = %" PRIu64 ", hand = %u, turn = %d\n",
+                  HASH_KEY, HAND_B, turn );
+             ptree->amove_hash[ply] = 0U;
+           }
+         else
+#endif
+           {
+             ptree->anext_move[ply].next_phase = next_evasion_genall;
+             ptree->current_move[ply]          = ptree->amove_hash[ply];
+             return 1;
+           }
+       }
+
+    case next_evasion_genall:
+      {
+       unsigned int * restrict pmove;
+       int * restrict psortv;
+       unsigned int move;
+       int n, i, j, sortv;
+
+       ptree->anext_move[ply].next_phase = next_evasion_misc;
+       ptree->anext_move[ply].move_last = pmove = ptree->move_last[ply-1];
+       n = (int)( ptree->move_last[ply] - pmove );
+       psortv = ptree->sort_value;
+
+       for ( i = n-1; i >= 0; i-- )
+         {
+           move = pmove[i];
+           if ( move == ptree->amove_hash[ply] )
+             {
+               sortv    = INT_MIN;
+               pmove[i] = 0;
+             }
+           else if ( I2PieceMove(move) == king )
+             {
+               sortv = p_value_ex[UToCap(move)+15] * 2;
+             }
+           else {
+             sortv  = swap( ptree, move, INT_MIN, INT_MAX, turn );
+             sortv += estimate_score_diff( ptree, move, turn );
+           }
+           psortv[i] = sortv;
+         }
+
+       /* insertion sort */
+       psortv[n] = INT_MIN;
+       for ( i = n-2; i >= 0; i-- )
+         {
+           sortv = psortv[i];  move = pmove[i];
+           for ( j = i+1; psortv[j] > sortv; j++ )
+             {
+               psortv[j-1] = psortv[j];  pmove[j-1] = pmove[j];
+             }
+           psortv[j-1] = sortv;  pmove[j-1] = move;
+         }
+      }
+
+    default:
+      assert( ptree->anext_move[ply].next_phase == next_evasion_misc );
+      while ( ptree->anext_move[ply].move_last < ptree->move_last[ply] )
+       {
+         if ( *( ptree->anext_move[ply].move_last ) )
+           {
+             ptree->current_move[ply] = *(ptree->anext_move[ply].move_last++);
+             return 1;
+           }
+         ptree->anext_move[ply].move_last++;
+       }
+    }
+  return 0;
+}
diff --git a/param.h b/param.h
new file mode 100644 (file)
index 0000000..e9cecce
--- /dev/null
+++ b/param.h
@@ -0,0 +1,15 @@
+#define DPawn            87 /*  174 */
+#define DLance          235 /*  470 */
+#define DKnight         254 /*  508 */
+#define DProPawn        530 /*  617 */
+#define DProLance       482 /*  717 */
+#define DSilver         371 /*  742 */
+#define DProKnight      500 /*  754 */
+#define DProSilver      489 /*  860 */
+#define DGold           447 /*  894 */
+#define DBishop         571 /* 1142 */
+#define DRook           647 /* 1294 */
+#define DHorse          832 /* 1403 */
+#define DDragon         955 /* 1602 */
+#define DKing         15000
+
diff --git a/phash.c b/phash.c
new file mode 100644 (file)
index 0000000..8592ee5
--- /dev/null
+++ b/phash.c
@@ -0,0 +1,275 @@
+#include "shogi.h"\r
+\r
+static unsigned short tab[] = {\r
+5866,14081,15663,4534,14969,3034,8274,7570,\r
+14571,15428,2921,37,2534,4727,660,249,\r
+8308,3662,15794,10079,13857,13019,6070,9141,\r
+3942,14629,6891,11561,12156,4793,11132,12989,\r
+10044,16304,9389,2228,5053,3789,5988,4479,\r
+8719,13901,15524,3098,7570,12949,1074,0,\r
+10079,16233,7531,14642,13600,8087,0,11690,\r
+8579,15413,6522,1076,2677,6914,10881,13803,\r
+13806,15789,14642,2135,15427,14023,14079,7708,\r
+3602,0,4976,10910,4821,4543,5455,9368,\r
+4201,9970,10647,15130,10079,15020,5558,15902,\r
+7858,2962,10386,2155,14641,12308,8021,8170,\r
+2490,10528,15427,14629,10528,15136,999,1883,\r
+14912,10788,6360,3677,14960,12257,2294,12614,\r
+8698,12433,9867,12663,16016,11332,8568,8348,\r
+0,3228,8594,11249,6674,3098,9297,10077,\r
+10340,5803,5420,6070,660,5676,1,9497,\r
+8700,14264,5846,12433,16282,12561,12032,13732,\r
+8239,10731,7236,10286,2678,7321,13368,6594,\r
+9047,5291,8293,2809,3268,6485,10509,2277,\r
+10471,595,8887,15919,14413,15881,8827,13726,\r
+13975,14092,7634,1652,8753,6801,6568,15853,\r
+1022,5664,0,9303,15719,6128,6674,7433,\r
+157,9360,6555,12432,9593,9660,14081,13927,\r
+8702,13702,8663,5629,3691,16298,1573,902,\r
+1272,2376,1084,14447,14666,1692,15316,15129,\r
+3833,920,8348,15839,15902,15635,10340,6603,\r
+1764,9634,3833,2470,4704,9646,385,13200,\r
+3009,1562,6846,6598,15861,8924,11762,3766,\r
+9095,431,6599,1987,15902,11064,4972,12175,\r
+14642,13857,6130,5833,13857,12112,8170,9867,\r
+2569,9648,1883,10205,12365,6801,5222,14506,\r
+1819,5142,2172,5291,15542,12112,2092,5560,\r
+4538,5461,15059,11773,15884,2099,6876,11914,\r
+3833,4972,8164,6240,12487,1341,10731,11762,\r
+14548,4471,5044,7576,2392,16129,8175,7559,\r
+12559,15861,6396,2926,7618,8417,15759,0,\r
+9095,3510,7247,1712,16345,2209,8055,0,\r
+319,12209,13144,15159,8238,7822,5014,10077,\r
+2284,7177,6555,15861,14479,2510,8170,11806,\r
+12149,12440,14185,11762,11552,8260,11864,11728,\r
+15046,11561,4707,13420,3615,2233,2277,10668,\r
+2228,8016,1813,2677,5240,6594,6636,9911,\r
+1737,4396,12500,9682,7176,2027,12500,5244,\r
+12112,1768,14571,12663,6729,3662,8170,15641,\r
+15316,9648,5373,5475,6522,14571,3662,15902,\r
+1652,9648,2228,8348,902,5988,9150,13250,\r
+13411,4675,431,5507,10616,13987,15316,1378,\r
+13832,13356,10087,9543,9093,8065,10497,8228,\r
+11762,616,12968,5411,9648,12487,9463,15597,\r
+11292,13985,14482,14600,1705,4678,12020,8828,\r
+6210,9481,14980,5738,5990,14447,1569,8618,\r
+2273,8543,1819,16158,12447,12470,10160,4725,\r
+10778,1412,8040,4300,9550,568,7394,592,\r
+9481,15680,3476,16128,7660,1214,359,6181,\r
+8618,4067,14699,13368,514,11355,8914,3801,\r
+14520,8885,10434,8274,7709,4312,7243,12633,\r
+4867,5981,4538,2490,3034,5558,6801,7512,\r
+14971,4315,4905,11682,8845,3732,1475,11661,\r
+10189,1741,11667,5605,2656,9573,10898,2796,\r
+1817,15216,11152,470,5988,6164,4972,10386,\r
+13128,7247,3268,6729,4300,13101,8568,12663,\r
+13849,3600,9718,11203,10528,13732,5251,14148,\r
+8568,13128,10205,11332,1712,12821,9557,12753,\r
+10505,5276,109,10394,10122,9809,3513,16093,\r
+2490,9943,14798,15084,4598,5174,15648,13109,\r
+0,6971,15426,14500,14571,6831,2623,6801,\r
+6522,15388,3228,11053,0,2902,4285,13853,\r
+14830,5373,15137,10087,3268,2569,6284,2902,\r
+1483,3838,12159,4764,15130,6846,6957,12499,\r
+4604,2739,14629,996,4867,13420,7791,5263,\r
+8119,10088,4128,7950,11875,16244,1147,3473,\r
+3268,15869,12821,11152,9922,1987,8238,15271,\r
+852,6921,4155,7857,11187,2275,14224,15725,\r
+9967,4479,6522,11152,2457,5962,13732,10088,\r
+11226,11359,5053,13420,3727,12487,3823,13412,\r
+13732,5962,11005,11173,8719,4354,6821,11421,\r
+15640,4769,14868,9369,215,8176,2363,1930,\r
+4124,11338,5373,2135,5253,10648,6220,5853,\r
+2741,12020,14070,14571,7476,9011,11415,1306,\r
+5318,13418,7293,15364,8898,3402,11976,9325,\r
+1562,7366,3395,10762,7144,2336,13458,4538,\r
+1159,1987,11652,12964,13513,541,13792,9741,\r
+10840,16129,10917,4534,13600,5462,2357,3890,\r
+6299,11315,13376,13820,13369,4450,14282,3510,\r
+10008,2381,9301,10165,4832,13042,3789,11751,\r
+8021,14286,9341,436,9171,8623,12745,12738,\r
+567,13996,3654,9495,844,8260,15108,2851,\r
+10351,2756,8572,3694,8851,5833,4280,12168,\r
+9550,9095,1652,6594,2534,3662,12009,6827,\r
+7447,2228,6555,15919,2294,6522,6674,0,\r
+13128,15478,3098,14571,1573,13117,16336,3422,\r
+12751,4635,9808,13171,11875,14148,14759,15680,\r
+610,780,14127,15067,12717,11768,2223,4745,\r
+2111,4363,6821,12230,13200,16093,410,15205,\r
+3838,15020,12230,3473,7951,2926,981,13414,\r
+3034,9835,3875,7247,15776,11053,10533,6393,\r
+6729,1712,12233,10088,5152,1378,6043,3871,\r
+6043,12487,15527,11769,12308,5962,11864,10804,\r
+3268,14005,13662,10647,4972,15137,14485,7784,\r
+7275,410,6555,2470,7074,359,12751,12054,\r
+8851,2993,9487,13270,9267,2370,8119,14112,\r
+6639,157,10245,16121,9967,14912,10307,8011,\r
+12094,2470,10322,3570,6154,1453,15084,14801,\r
+3823,7259,780,4972,13047,14500,2569,5833,\r
+56,14601,2690,5036,788,46,2738,9922,\r
+11332,10619,8011,13128,3268,431,13412,8851,\r
+14748,5036,12185,13042,10030,11716,100,16205,\r
+7951,5738,8417,10757,6463,7114,1183,14798,\r
+10205,9721,15359,10074,8727,4587,11875,14615,\r
+10340,9171,9171,4686,7731,4269,13042,8574,\r
+16298,7024,10309,2858,4904,7223,8238,7512,\r
+4556,3532,15222,2161,1162,6476,3221,10290,\r
+11229,15137,14921,1319,4925,1991,7817,7427,\r
+15089,9366,920,3875,4641,11787,14255,4915,\r
+7588,15555,13106,16014,12882,10324,341,1331,\r
+10685,7950,12292,10230,15336,7431,7576,6158,\r
+5058,12149,2777,13434,5263,15769,9877,2704,\r
+10300,867,1443,5285,2155,4474,935,12586,\r
+12601,158,16191,8119,3726,3554,10398,13418,\r
+8170,4867,14642,15478,1712,10136,6674,0,\r
+46,9867,3766,12433,6057,3972,2156,852,\r
+2144,9856,14761,11491,46,363,10561,4484,\r
+999,9557,2902,7323,15084,8274,16087,6679,\r
+6867,6971,2914,586,6240,5988,10386,8304,\r
+3662,10088,5988,12821,7409,8308,15931,14376,\r
+14700,15998,4484,1766,15794,3833,2464,4342,\r
+1358,319,10099,15776,15839,1530,8538,7800,\r
+3641,5569,7469,2104,8314,8976,5962,11857,\r
+10330,8293,12356,1399,1991,5415,10497,15478,\r
+15931,8308,11608,10167,4185,9369,1658,6193,\r
+5962,5132,12322,319,7802,4707,3034,11308,\r
+9559,10788,2228,8339,13513,5222,1712,3098,\r
+1987,2719,1548,15427,13361,13736,5139,1255,\r
+11064,8011,985,6135,788,2761,6522,5362,\r
+13128,3476,6164,12032,2902,15881,11053,14538,\r
+12964,14730,3751,12890,396,1132,6164,7938,\r
+3165,7677,12218,7007,4824,6266,4198,9127,\r
+12821,6463,199,6522,5462,1084,7232,15717,\r
+3354,2788,6294,11857,14174,2235,6135,7808,\r
+15931,10377,1168,9162,7176,3595,10046,1960,\r
+3726,1723,6779,10955,11201,4721,661,7247,\r
+5988,11291,9095,8555,7017,5975,14500,15822,\r
+10887,7999,9648,15908,2938,8293,14629,4233,\r
+8419,5141,12427,9360,2948,9321,13473,1134,\r
+87,4180,2284,8822,3893,15653,15668,12175,\r
+7951,12668,13119,7839,4793,4686,914,9481,\r
+11912,13196,4235,15293,5704,9063,1605,15640,\r
+13270,1192,9967,8698,5576,3059,4067,11809,\r
+5420,7691,16087,764,12487,2273,14224,13412,\r
+5373,12663,788,12433,8870,15902,14019,3966,\r
+1104,11153,13117,8913,46,9922,15240,8260,\r
+9874,1712,9096,7708,4544,15601,0,10529,\r
+7419,9404,653,4067,10717,4901,10009,7229,\r
+9867,7620,1412,14284,9931,8845,13975,8238,\r
+10941,10205,678,11308,14985,12099,3268,11120,\r
+14148,7900,5934,10099,12903,6274,9648,2851,\r
+972,5149,9506,12102,723,15873,14497,5447,\r
+13505,13658,13128,4699,11152,0,0,7808,\r
+2623,6674,9557,7920,10004,14081,0,15478,\r
+12498,7162,13662,14438,6939,10841,6599,7074,\r
+2129,9303,3614,5121,13626,14806,13096,5275,\r
+12032,11431,12265,242,12651,6465,11153,15635,\r
+6154,7864,3263,7708,13216,9466,4929,4763,\r
+16121,12949,6801,14244,6289,3766,8913,3228,\r
+10099,4198,11895,286,13119,10778,12230,7238,\r
+3614,14081,7323,4050,6846,14629,13420,9427,\r
+5460,5130,10528,15705,6369,8361,1212,8866,\r
+12821,15427,7323,2777,9648,8744,5386,8241,\r
+11875,14112,14770,15369,9813,6750,13732,6594,\r
+2464,11682,2031,15129,3532,12112,4831,4354,\r
+2275,10376,11226,11611,8313,9590,14500,8598,\r
+13403,4316,15388,13458,961,208,5995,1225,\r
+6455,5932,11987,2902,13128,1224,1003,7409,\r
+3028,650,13436,8485,6653,911,9425,11421,\r
+9554,10993,15293,514,6670,14578,4972,9874,\r
+8483,2534,14969,1934,14154,8926,11830,8784,\r
+2987,9634,6670,13501,13957,4260,5761,15347,\r
+7991,13414,7159,7233,14206,11665,6715,11079,\r
+3545,5185,15639,14307,9338,8971,15994,5645,\r
+3098,14081,788,8170,10188,8016,5988,15919,\r
+12788,14960,10214,12606,11152,2470,13420,2927,\r
+5240,7370,9648,10099,2039,4846,10610,11823,\r
+13270,14761,5962,7512,10079,4867,8260,2135,\r
+1052,10823,5729,10395,14361,13382,12200,8162,\r
+5117,7531,13361,14520,10602,8685,3654,9777,\r
+16263,6135,6389,11745,10383,8550,12618,10340,\r
+4128,15459,7062,5135,9047,9346,5897,15479,\r
+7268,5576,0,14937,12736,5545,10079,6507,\r
+3238,3204,9865,5843,12487,198,8251,13195,\r
+158,8913,6598,4373,15991,13857,3615,11106,\r
+3244,10654,6394,6183,11633,3098,12257,15427,\r
+1768,7209,11987,963,13857,7247,16046,7239,\r
+13200,11773,2914,12927,11669,13011,1905,9089,\r
+16176,3743,158,5222,12717,5825,16087,9519,\r
+9227,15563,1712,8511,11005,4867,13200,13106,\r
+10788,3606,8680,3447,5833,3709,4526,10847,\r
+2871,6000,2204,15769,2969,7617,15976,7618,\r
+4067,10757,15316,6476,10509,8772,9095,0,\r
+8996,410,14742,7239,10532,9406,7419,15903,\r
+5437,5560,12608,9141,3986,14358,7409,3992,\r
+3221,6170,11821,508,6434,1442,4260,3813,\r
+8308,6456,3534,431,4538,3406,12435,5643,\r
+7144,8870,9186,3775,1817,9905,7951,4336,\r
+2273,12264,6513,2993,16270,5541,5077,6263,\r
+1259,2559,1675,16218,1790,12804,15098,4445,\r
+10336,15216,12144,8618,4573,13679,15000,10189,\r
+2209,4583,5353,13784,2623,7720,5833,11064,\r
+10088,10077,10610,6786,10939,10867,1768,8119,\r
+7394,12056,3789,1074,15413,10527,7247,12487,\r
+8568,10136,2228,13412,4840,1652,6740,11322,\r
+5037,2910,5174,10340,2135,8011,11895,11895,\r
+109,11957,14336,13234,8225,14343,9063,9819,\r
+13517,11635,13549,14936,988,3809,5833,7857,\r
+13462,297,7668,14482,4316,10848,2569,13931,\r
+5593,12056,11103,14170,448,902,1768,11552,\r
+6043,0,0,8646,10391,0,15316,3737,\r
+10594,11026,13280,14667,5713,4057,2787,4191,\r
+3838,7247,8772,14185,15641,8772,0,14081,\r
+0,9429,17,613,7428,15131,15651,14350,\r
+4365,15856,9521,3228,7950,3395,0,6594,\r
+11078,14975,6889,10768,4288,6707,7175,2235,\r
+10896,911,7707,7592,12916,15570,15644,6997,\r
+12523,14757,11895,7109,16279,12969,11690,0,\r
+8854,16304,8568,11334,15641,15478,2275,6193,\r
+7323,5230,9835,12821,1652,12477,5044,359,\r
+12487,13881,10731,8246,14642,14885,6555,15919,\r
+13857,1982,7646,12528,12009,7310,12310,3193,\r
+359,1483,5322,10476,46,3751,3766,6729,\r
+4512,13853,5558,12736,1733,2718,9956,7857,\r
+6519,2187,12964,12949,750,8877,15136,3742,\r
+4495,13851,3811,906,11592,9943,920,10806,\r
+10442,12561,5035,988,15861,8024,10272,16372,\r
+13353,15946,7330,4834,9414,8267,1668,12498,\r
+4530,9162,8648,3883,9451,3900,2028,12427,\r
+11203,3071,5645,10228,11875,8198,4563,215,\r
+3614,5717,11332,1617,11382,13987,12626,11857,\r
+12156,6513,13496,6997,16158,9093,6725,13737,\r
+5890,10008,14447,5475,12215,141,16192,10200,\r
+4450,6688,11090,16109,12256,9027,15355,3422,\r
+10079,14571,13101,9967,12296,3460,8348,15413,\r
+5222,11762,3823,13412,6729,6599,10528,9922,\r
+11152,9171,5362,5373,750,8969,1652,6220,\r
+5373,2569,3742,15119,10340,999,10088,10731,\r
+1028,3228,7369,15256,11822,12904,8121,11641,\r
+11158,5016,10725,8412,1183,9674,11806,12112,\r
+2623,15516,4226,10021,13316,12075,792,4972,\r
+8506,8921,6133,14718,567,4349,13420,5953,\r
+2265,11902,10019,16265,16312,0,9922,3009,\r
+8170,3473,10757,3567,2825,6915,5174,4299,\r
+0,8274,6292,295,6522,1475,359,4538,\r
+5358,5174,3008,6317,12688,4165,752,12052,\r
+10008,3912,7431,13364,9894,13524,284,16013,\r
+9820,11295,1144,2845,3538,10678,13806,1469,\r
+14210,7870,3766,10528,13642,10823,4200,8031,\r
+4671,14093,5541,1214,4115,3286,8217,8018 };\r
+\r
+\r
+unsigned int phash( unsigned int move, int turn )\r
+{\r
+  unsigned int a, b;\r
+  \r
+  move |= ( (unsigned int)turn << 31 );\r
+  move += 0x69fe378e;\r
+  move ^= ( move >> 16 );\r
+  move += ( move << 8 );\r
+  move ^= ( move >> 4 );\r
+  b     = ( move >> 7 ) & 0x7ff;\r
+  a     = move >> 18;\r
+  \r
+  return a ^ tab[b];\r
+}\r
diff --git a/ponder.c b/ponder.c
new file mode 100644 (file)
index 0000000..2eb8b7a
--- /dev/null
+++ b/ponder.c
@@ -0,0 +1,106 @@
+#include <stdlib.h>
+#include <limits.h>
+#include "shogi.h"
+
+
+int
+ponder( tree_t * restrict ptree )
+{
+  const char *str;
+  unsigned int move;
+  int iret;
+
+  if ( ( game_status & ( mask_game_end | flag_noponder | flag_nopeek ) )
+       || abs( last_root_value ) > score_max_eval
+       || ! record_game.moves
+       || sec_limit_up == UINT_MAX ) { return 1; }
+
+  ponder_nmove = gen_legal_moves( ptree, ponder_move_list );
+
+  if ( get_elapsed( &time_start ) < 0 ) { return -1; }
+
+  Out( "\nSearch a move to ponder\n\n" );
+  OutCsaShogi( "info ponder start\n" );
+
+  game_status |= flag_puzzling;
+  iret         = iterate( ptree, 0 );
+  game_status &= ~flag_puzzling;
+  if ( iret < 0 ) { return iret; }
+
+  if ( game_status & ( flag_quit | flag_quit_ponder | flag_suspend ) )
+    {
+      OutCsaShogi( "info ponder end\n" );
+      return 1;
+    }
+
+  if ( abs(last_root_value) > score_max_eval )
+    {
+      OutCsaShogi( "info ponder end\n" );
+      return 1;
+    }
+
+  ponder_move = move = last_pv.a[1];
+  str = str_CSA_move( move );
+  Out( "\nPonder on %c%s (%+.2f)\n\n",
+       ach_turn[root_turn], str, (double)last_root_value / 100.0 );
+
+  iret = make_move_root( ptree, move, ( flag_rep | flag_rejections ) );
+  if ( iret < 0 )
+    {
+      OutCsaShogi( "info ponder end\n" );
+      return iret;
+    }
+  
+  if ( game_status & mask_game_end )
+    {
+      OutCsaShogi( "info ponder end\n" );
+      unmake_move_root( ptree, move );
+      return 1;
+    }
+  
+  if ( get_elapsed( &time_start ) < 0 ) { return -1; }
+
+  game_status |= flag_pondering;
+
+  iret = iterate( ptree, 0 );
+  if ( game_status & flag_thinking )
+    {
+      game_status &= ~flag_thinking;
+      if ( iret < 0 ) { return iret; }
+
+      iret = com_turn_start( ptree, flag_from_ponder );
+      if ( iret < 0 ) { return iret; }
+      
+      return 2;
+    }
+  OutCsaShogi( "info ponder end\n" );
+  game_status &= ~flag_pondering;
+  unmake_move_root( ptree, move );
+
+  return iret;
+}
+
+
+#if defined(MNJ_LAN)
+int
+analyze( tree_t * restrict ptree )
+{
+  int iret;
+
+  if ( game_status & mask_game_end ) { return 1; }
+
+  iret = get_elapsed( &time_start );
+  if ( iret < 0 ) { return iret; }
+
+  game_status |=  flag_pondering;
+  iret = iterate( ptree, 0 );
+  game_status &= ~flag_pondering;
+
+  if ( abs(last_root_value) > score_max_eval )
+    {
+      MnjOut( "pid=%d confident\n", mnj_posi_id );
+    }
+
+  return iret;
+}
+#endif
diff --git a/problem.c b/problem.c
new file mode 100644 (file)
index 0000000..4980e9a
--- /dev/null
+++ b/problem.c
@@ -0,0 +1,102 @@
+#include "shogi.h"
+
+int
+solve_problems( tree_t * restrict ptree, unsigned int nposition )
+{
+  const char *str_move;
+  uint64_t total_node;
+  unsigned int game_status_save, move, uposition, te1, te0;
+  int iret, success, failure, ianswer, istatus, iresult;
+
+  success = failure = 0;
+  total_node = 0;
+  if ( get_elapsed( &te0 ) < 0 ) { return -1; };
+
+  for ( uposition = 0; uposition < nposition; uposition++ )
+    {
+      istatus = in_CSA( ptree, &record_problems, NULL,
+                       ( flag_nomake_move | flag_detect_hang
+                         | flag_rejections ) );
+      if ( istatus < 0 ) { return istatus; }
+
+      if ( istatus > record_next )
+       {
+         snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+                   record_problems.lines, str_bad_record );
+         str_error = str_message;
+         return -2;
+       }
+
+      /* examine all of answers */
+      Out( "Answers:" );
+      for ( ianswer = 0; ianswer < MAX_ANSWER; ianswer++ )
+       {
+         str_move = &( record_problems.info.str_move[ianswer][0] );
+         if ( str_move[0] == '\0' ) { break; }
+         if ( ( root_turn && str_move[0] != '-' )
+              || ( ! root_turn && str_move[0] != '+' ) )
+           {
+             snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+                       record_problems.lines,
+                       "Answers has invalid sign of turn." );
+             str_error = str_message;
+             return -2;
+           }
+
+         iret = interpret_CSA_move( ptree, &move, str_move+1 );
+         if ( iret < 0 ) { return iret; }
+
+         iret = make_move_root( ptree, move, ( flag_detect_hang | flag_rep
+                                               | flag_nomake_move ) );
+         if ( iret < 0 ) { return iret; }
+
+         Out( "%s ", str_move );
+       }
+      Out( "\n" );
+      if ( ! ianswer )
+       {
+         snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+                   record_problems.lines,
+                   "No answers in the record" );
+         str_error = str_message;
+         return -2;
+       }
+
+      iret = out_board( ptree, stdout, 0, 0 );
+      if ( iret < 0 ) { return iret; }
+
+      if ( get_elapsed( &time_start ) < 0 ) { return -1; };
+      time_turn_start = time_start;
+
+      game_status_save  = game_status;
+      game_status      |= flag_problem | flag_nopeek | flag_thinking;
+      iresult           = iterate( ptree, 0 );
+      game_status       = game_status_save;
+      if ( iresult < 0 ) { return iresult; }
+
+      if ( iresult ) { success++; }
+      else           { failure++; }
+
+      total_node += ptree->node_searched;
+
+      str_move = str_CSA_move( last_pv.a[1] );
+      Out( "problem #%d answer=%s -- %s (correct=%d, incorrect=%d)\n\n",
+          success+failure, str_move, iresult ? "correct" : "incorrect",
+          success, failure );
+
+      if ( istatus == record_eof ) { break; }
+      if ( istatus == record_misc )
+       {
+         iret = record_wind( &record_problems );
+         if ( iret < 0 )           { return iret; }
+         if ( iret == record_eof ) { break; }
+       }
+    }
+
+  if ( get_elapsed( &te1 ) < 0 ) { return -1; }
+
+  Out( "Total Nodes:   %" PRIu64 "\n", total_node );
+  Out( "Total Elapsed: %.2f\n", (double)( te1 - te0 ) / 1000.0 );
+
+  return 1;
+}
diff --git a/proce.c b/proce.c
new file mode 100644 (file)
index 0000000..bb41877
--- /dev/null
+++ b/proce.c
@@ -0,0 +1,1654 @@
+#include <ctype.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "shogi.h"
+
+/* unacceptable when the program is thinking, or quit pondering */
+#define AbortDifficultCommand                                              \
+         if ( game_status & flag_thinking )                               \
+           {                                                              \
+             str_error = str_busy_think;                                  \
+             return -2;                                                   \
+           }                                                              \
+         else if ( game_status & ( flag_pondering | flag_puzzling ) )     \
+           {                                                              \
+             game_status |= flag_quit_ponder;                             \
+             return 2;                                                    \
+           }
+
+#if defined(MINIMUM)
+#  define CmdBook(x,y) cmd_book(y);
+static int cmd_book( char **lasts );
+#else
+#  define CmdBook(x,y) cmd_book(x,y);
+static int cmd_learn( tree_t * restrict ptree, char **lasts );
+static int cmd_book( tree_t * restrict ptree, char **lasts );
+#endif
+
+#if ! defined(NO_STDOUT)
+static int cmd_stress( char **lasts );
+#endif
+
+#if defined(DEKUNOBOU)
+static int cmd_dek( char **lasts );
+#endif
+
+#if defined(CSA_LAN)
+static int proce_csalan( tree_t * restrict ptree );
+static int cmd_connect( tree_t * restrict ptree, char **lasts );
+#endif
+
+#if defined(MNJ_LAN)
+static int proce_mnj( tree_t * restrict ptree );
+static int cmd_mnj( tree_t * restrict ptree, char **lasts );
+static int cmd_mnjmove( tree_t * restrict ptree, char **lasts, int is_alter );
+#endif
+
+#if defined(TLP)
+static int cmd_thread( char **lasts );
+#endif
+
+#if defined(MPV)
+static int cmd_mpv( char **lasts );
+#endif
+
+static int proce_cui( tree_t * restrict ptree );
+static int cmd_usrmove( tree_t * restrict ptree, const char *str_move,
+                       char **last );
+static int cmd_move_now( void );
+static int cmd_ponder( char **lasts );
+static int cmd_limit( char **lasts );
+static int cmd_quit( void );
+static int cmd_beep( char **lasts );
+static int cmd_peek( char **lasts );
+static int cmd_hash( char **lasts );
+static int cmd_ping( void );
+static int cmd_suspend( void );
+static int cmd_problem( tree_t * restrict ptree, char **lasts );
+static int cmd_display( tree_t * restrict ptree, char **lasts );
+static int cmd_move( tree_t * restrict ptree, char **lasts );
+static int cmd_new( tree_t * restrict ptree, char **lasts );
+static int cmd_read( tree_t * restrict ptree, char **lasts );
+static int cmd_resign( tree_t * restrict ptree, char **lasts );
+static int cmd_time( char **lasts );
+static int is_move( const char *str );
+
+
+int
+procedure( tree_t * restrict ptree )
+{
+#if defined(CSA_LAN)
+  if ( sckt_csa != SCKT_NULL ) { return proce_csalan( ptree ); }
+#endif
+#if defined(MNJ_LAN)
+  if ( sckt_mnj != SCKT_NULL ) { return proce_mnj( ptree ); }
+#endif
+
+  return proce_cui( ptree );
+}
+
+
+static int
+proce_cui( tree_t * restrict ptree )
+{
+  const char *token;
+  char *last;
+
+  token = strtok_r( str_cmdline, str_delimiters, &last );
+
+  if ( token == NULL || *token == '#' ) { return 1; }
+  if ( is_move( token ) ) { return cmd_usrmove( ptree, token, &last ); }
+  if ( ! strcmp( token, "s" ) )         { return cmd_move_now(); }
+  if ( ! strcmp( token, "beep" ) )      { return cmd_beep( &last); }
+  if ( ! strcmp( token, "book" ) )      { return CmdBook( ptree, &last ); }
+  if ( ! strcmp( token, "display" ) )   { return cmd_display( ptree, &last ); }
+  if ( ! strcmp( token, "hash" ) )      { return cmd_hash( &last ); }
+  if ( ! strcmp( token, "limit" ) )     { return cmd_limit( &last ); }
+  if ( ! strcmp( token, "move" ) )      { return cmd_move( ptree, &last ); }
+  if ( ! strcmp( token, "new" ) )       { return cmd_new( ptree, &last ); }
+  if ( ! strcmp( token, "peek" ) )      { return cmd_peek( &last ); }
+  if ( ! strcmp( token, "ping" ) )      { return cmd_ping(); }
+  if ( ! strcmp( token, "ponder" ) )    { return cmd_ponder( &last ); }
+  if ( ! strcmp( token, "problem" ) )   { return cmd_problem( ptree, &last ); }
+  if ( ! strcmp( token, "quit" ) )      { return cmd_quit(); }
+  if ( ! strcmp( token, "read" ) )      { return cmd_read( ptree, &last ); }
+  if ( ! strcmp( token, "resign" ) )    { return cmd_resign( ptree, &last ); }
+  if ( ! strcmp( token, "suspend" ) )   { return cmd_suspend(); }
+  if ( ! strcmp( token, "time" ) )      { return cmd_time( &last ); }
+#if defined(CSA_LAN)
+  if ( ! strcmp( token, "connect" ) )   { return cmd_connect( ptree, &last ); }
+#endif
+#if defined(MNJ_LAN)
+  if ( ! strcmp( token, "mnj" ) )       { return cmd_mnj( ptree, &last ); }
+#endif
+#if defined(DEKUNOBOU)
+  if ( ! strcmp( token, "dekunobou" ) ) { return cmd_dek( &last ); }
+#endif
+#if defined(MPV)
+  if ( ! strcmp( token, "mpv" ) )       { return cmd_mpv( &last ); }
+#endif
+#if defined(TLP)
+  if ( ! strcmp( token, "tlp" ) )       { return cmd_thread( &last ); }
+#endif
+#if ! defined(NO_STDOUT)
+  if ( ! strcmp( token, "stress" ) )    { return cmd_stress( &last ); }
+#endif
+#if ! defined(MINIMUM)
+  if ( ! strcmp( token, "learn" ) )     { return cmd_learn( ptree, &last ); }
+#endif
+
+  str_error = str_bad_cmdline;
+  return -2;
+}
+
+
+#if defined(CSA_LAN)
+static int
+proce_csalan( tree_t * restrict ptree )
+{
+  const char *token;
+  char *last;
+
+  token = strtok_r( str_cmdline, str_delimiters, &last );
+    
+  if ( token == NULL ) { return 1; }
+  if ( *token == ach_turn[client_turn] && is_move( token+1 ) )
+    {
+      char *ptr;
+      long l;
+
+      token = strtok_r( NULL, str_delimiters, &last );
+      if ( token == NULL || *token != 'T' )
+       {
+         str_error = str_bad_cmdline;
+         return -1;
+       }
+      
+      l = strtol( token+1, &ptr, 0 );
+      if ( token+1 == ptr || l == LONG_MAX || l < 1 )
+       {
+         str_error = str_bad_cmdline;
+         return -1;
+       }
+
+      adjust_time( (unsigned int)l, client_turn );
+      Out( "  elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
+      return 1;
+    }
+  if ( *token == ach_turn[Flip(client_turn)] && is_move( token+1 ) )
+    {
+      return cmd_usrmove( ptree, token+1, &last );
+    }
+  if ( ! strcmp( token, str_resign ) ) { return cmd_resign( ptree, &last ); }
+  if ( ! strcmp( token, "#WIN" )
+       || ! strcmp( token, "#LOSE" )
+       || ! strcmp( token, "#DRAW" )
+       || ! strcmp( token, "#CHUDAN" ) )
+    {
+      if ( game_status & ( flag_thinking | flag_pondering | flag_puzzling ) )
+       {
+         game_status |= flag_suspend;
+         return 2;
+       }
+      
+      ShutdownClient;
+      
+      if ( client_ngame == client_max_game ) { return cmd_quit(); }
+
+      return client_next_game( ptree, client_str_addr, (int)client_port );
+    }
+  
+  return 1;
+}
+#endif
+
+
+#if defined(MNJ_LAN)
+static int
+proce_mnj( tree_t * restrict ptree )
+{
+  const char *token;
+  char *last;
+  int iret;
+
+  token = strtok_r( str_cmdline, str_delimiters, &last );
+  if ( token == NULL ) { return 1; }
+
+  if ( ! strcmp( token, "new" ) )
+    {
+      iret = cmd_suspend();
+      if ( iret != 1 ) { return iret; }
+
+      mnj_posi_id = 0;
+      iret = cmd_new( ptree, &last );
+      if ( iret < 0 ) { return iret; }
+
+      return analyze( ptree );
+    }
+  if ( ! strcmp( token, "idle" ) )  { return cmd_suspend(); }
+  if ( ! strcmp( token, "alter" ) ) { return cmd_mnjmove( ptree, &last, 1 ); }
+  if ( ! strcmp( token, "move" ) )  { return cmd_mnjmove( ptree, &last, 0 ); }
+
+  str_error = str_bad_cmdline;
+  return -2;
+}
+
+
+static int
+cmd_mnjmove( tree_t * restrict ptree, char **lasts, int is_alter )
+{
+  const char *str1 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+  long lid;
+  unsigned int move;
+  int iret;
+
+  if ( sckt_mnj == SCKT_NULL ||  str1 == NULL || str2 == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -1;
+    }
+
+  lid = strtol( str2, &ptr, 0 );
+  if ( ptr == str2 || lid == LONG_MAX || lid < 1 )
+    {
+      str_error = str_bad_cmdline;
+      return -1;
+    }
+
+  AbortDifficultCommand;
+  if ( is_alter ) { unmake_move_root( ptree, mnj_move_last ); };
+
+  iret = interpret_CSA_move( ptree, &move, str1 );
+  if ( iret < 0 ) { return iret; }
+    
+  iret = get_elapsed( &time_turn_start );
+  if ( iret < 0 ) { return iret; }
+
+  mnj_posi_id   = (int)lid;
+  mnj_move_last = move;
+
+  iret = make_move_root( ptree, move, ( flag_history | flag_time | flag_rep
+                                       | flag_detect_hang
+                                       | flag_rejections ) );
+  if ( iret < 0 ) { return iret; }
+  
+#  if ! defined(NO_STDOUT)
+  iret = out_board( ptree, stdout, 0, 0 );
+  if ( iret < 0 ) { return iret; }
+#  endif
+
+  return analyze( ptree );
+}
+#endif
+
+
+static int
+is_move( const char *str )
+{
+  if ( isdigit( (int)str[0] ) && isdigit( (int)str[1] )
+       && isdigit( (int)str[2] ) && isdigit( (int)str[3] )
+       && isupper( (int)str[4] ) && isupper( (int)str[5] )
+       && str[6] == '\0' ) { return 1; }
+
+  return 0;
+}
+
+
+static int
+cmd_move_now( void )
+{
+  if ( game_status & flag_thinking ) { game_status |= flag_move_now; }
+
+  return 1;
+}
+
+
+static int
+cmd_usrmove( tree_t * restrict ptree, const char *str_move, char **lasts )
+{
+  const char *str;
+  char *ptr;
+  long lelapsed;
+  unsigned int move;
+  int iret;
+
+  if ( game_status & mask_game_end )
+    {
+      str_error = str_game_ended;
+      return -2;
+    }
+  
+  if ( game_status & flag_thinking )
+    {
+      str_error = str_busy_think;
+      return -2;
+    }
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( str == NULL ) { lelapsed = 0; }
+  else {
+    if ( *str != 'T' )
+      {
+       str_error = str_bad_cmdline;
+       return -2;
+      }
+    str += 1;
+    lelapsed = strtol( str, &ptr, 0 );
+    if ( ptr == str || lelapsed == LONG_MAX || lelapsed < 1 )
+      {
+       str_error = str_bad_cmdline;
+       return -2;
+      }
+  }
+
+  if ( game_status & ( flag_pondering | flag_puzzling ) )
+    {
+      int i;
+
+      for ( i = 0; i < ponder_nmove; i++ )
+       {
+         if ( ! strcmp( str_move, str_CSA_move(ponder_move_list[i]) ) )
+           {
+             break;
+           }
+       }
+      if ( i == ponder_nmove )
+       {
+#if defined(CSA_LAN)
+         if ( sckt_csa != SCKT_NULL ) { AbortDifficultCommand; }
+#endif
+
+#if defined(DEKUNOBOU)
+         if ( dek_ngame ) { AbortDifficultCommand; }
+#endif
+
+#if defined(CSASHOGI)
+         AbortDifficultCommand;
+#else
+         str_error = str_illegal_move;
+         return -2;
+#endif
+       }
+
+      if ( ( game_status & flag_puzzling )
+          || strcmp( str_move, str_CSA_move(ponder_move) ) )
+       {
+         ponder_move  = MOVE_PONDER_FAILED;
+         game_status |= flag_quit_ponder;
+         return 2;
+       }
+      else {
+       iret = renovate_time( Flip(root_turn) );
+       if ( iret < 0 ) { return iret; }
+       if ( lelapsed )
+         {
+           adjust_time( (unsigned int)lelapsed, Flip(root_turn) );
+         }
+
+       history_book_learn[ record_game.moves ].move_played = ponder_move;
+       history_book_learn[ record_game.moves ].hand_played
+         = ptree->rep_hand_list[ root_nrep-1 ];
+       history_book_learn[ record_game.moves ].key_played
+         = (unsigned int)ptree->rep_board_list[ root_nrep-1 ];
+
+       out_CSA( ptree, &record_game, ponder_move );
+
+       game_status      &= ~flag_pondering;
+       game_status      |= flag_thinking;
+       n_nobook_move    += 1;
+       set_search_limit_time( root_turn );
+
+       OutCsaShogi( "info ponder end\n" );
+
+       str = str_time_symple( time_turn_start - time_start );
+       Out( "    %6s          MOVE PREDICTION HIT\n"
+            "  elapsed: b%u, w%u\n", str, sec_b_total, sec_w_total );
+       return 1;
+      }
+    }
+
+  iret = interpret_CSA_move( ptree, &move, str_move );
+  if ( iret < 0 ) { return iret; }
+  move_evasion_pchk = 0;
+  iret = make_move_root( ptree, move, ( flag_rep | flag_history | flag_time
+                                       | flag_rejections
+                                       | flag_detect_hang ) );
+  if ( iret < 0 )
+      {
+
+#if defined(CSA_LAN)
+       if ( sckt_csa != SCKT_NULL )
+         {
+           if ( move_evasion_pchk )
+             {
+               str  = str_CSA_move( move_evasion_pchk );
+               iret = sckt_out( sckt_csa, "%c%s\n",
+                                ach_turn[Flip(root_turn)], str );
+               if ( iret < 0 ) { return iret; }
+             }
+           return cmd_suspend();
+         }
+#endif
+
+#if defined(DEKUNOBOU)
+       if ( dek_ngame )
+         {
+           if ( move_evasion_pchk )
+             {
+               dek_win += 1;
+               OutDek( "%%TORYO\n" );
+             }
+           return cmd_suspend();
+         }
+#endif
+
+       if ( move_evasion_pchk )
+         {
+           str = str_CSA_move( move_evasion_pchk );
+#if defined(CSASHOGI)
+           OutCsaShogi( "move%s\n", str );
+           return cmd_suspend();
+#else
+           snprintf( str_message, SIZE_MESSAGE, "perpetual check (%c%s)",
+                     ach_turn[Flip(root_turn)], str );
+           str_error = str_message;
+           return -2;
+#endif
+         }
+
+       return iret;
+      }
+
+  if ( lelapsed ) { adjust_time( (unsigned int)lelapsed, Flip(root_turn) ); }
+  Out( "  elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
+
+#if defined(CSA_LAN)
+  if ( sckt_csa != SCKT_NULL && ( game_status & flag_mated ) )
+    {
+      iret = sckt_out( sckt_csa, "%%TORYO\n" );
+      if ( iret < 0 ) { return iret; }
+    }
+#endif
+
+#if defined(DEKUNOBOU)
+  if ( dek_ngame && ( game_status & flag_drawn ) ) { OutDek( "%%TORYO\n" ); }
+#endif
+
+  if ( ! ( game_status & mask_game_end ) )
+    {
+      iret = com_turn_start( ptree, 0 );
+      if ( iret < 0 ) { return iret; }
+    }
+
+  return 1;
+}
+
+
+static int
+cmd_beep( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_nobeep; }
+  else if ( ! strcmp( str, str_off ) ) {  game_status |=  flag_nobeep; }
+  else {
+    str_error = str_bad_cmdline;
+    return -2;
+  }
+
+  return 1;
+}
+
+
+static int
+cmd_peek( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_nopeek; }
+  else if ( ! strcmp( str, str_off ) ) {  game_status |=  flag_nopeek; }
+  else {
+    str_error = str_bad_cmdline;
+    return -2;
+  }
+
+  return 1;
+}
+
+
+static int
+cmd_ponder( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_noponder; }
+  else if ( ! strcmp( str, str_off ) )
+    {
+      if ( game_status & ( flag_pondering | flag_puzzling ) )
+       {
+         game_status |= flag_quit_ponder;
+       }
+      game_status |= flag_noponder;
+    }
+  else {
+    str_error = str_bad_cmdline;
+    return -2;
+  }
+
+  return 1;
+}
+
+
+#if ! defined(NO_STDOUT)
+static int
+cmd_stress( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  if      ( ! strcmp( str, str_on  ) ) { game_status &= ~flag_nostress; }
+  else if ( ! strcmp( str, str_off ) ) { game_status |= flag_nostress; }
+  else {
+    str_error = str_bad_cmdline;
+    return -2;
+  }
+
+  return 1;
+}
+#endif
+
+
+static int
+#if defined(MINIMUM)
+cmd_book( char **lasts )
+#else
+cmd_book( tree_t * restrict ptree, char **lasts )
+#endif
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  int iret = 1;
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  if      ( ! strcmp( str, str_on ) )   { iret = book_on(); }
+  else if ( ! strcmp( str, str_off ) )  { iret = book_off(); }
+  else if ( ! strcmp( str, "narrow" ) ) { game_status |= flag_narrow_book; }
+  else if ( ! strcmp( str, "wide" ) )   { game_status &= ~flag_narrow_book; }
+#if ! defined(MINIMUM)
+  else if ( ! strcmp( str, "create" ) )
+    {
+      AbortDifficultCommand;
+
+      iret = book_create( ptree );
+      if ( iret < 0 ) { return iret; }
+
+      iret = ini_game( ptree, &min_posi_no_handicap, flag_history,
+                      NULL, NULL );
+      if ( iret < 0 ) { return iret; }
+
+      iret = get_elapsed( &time_turn_start );
+    }
+#endif
+  else {
+    str_error = str_bad_cmdline;
+    iret = -2;
+  }
+
+  return iret;
+}
+
+
+static int
+cmd_display( tree_t * restrict ptree, char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+  long l;
+  int iret;
+
+  if ( str != NULL )
+    {
+      l = strtol( str, &ptr, 0 );
+      if ( ptr == str )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      if      ( l == 1 ) { game_status &= ~flag_reverse; }
+      else if ( l == 2 ) { game_status |= flag_reverse; }
+      else {
+       str_error = str_bad_cmdline;
+       return -2;
+      }
+    }
+  
+  Out( "\n" );
+  iret = out_board( ptree, stdout, 0, 0 );
+  if ( iret < 0 ) { return iret; }
+#if ! defined(NO_LOGGING)
+  iret = out_board( ptree, pf_log, 0, 0 );
+  if ( iret < 0 ) { return iret; }
+#endif
+  Out( "\n" );
+
+  return 1;
+}
+
+
+static int
+cmd_ping( void )
+{
+  OutCsaShogi( "pong\n" );
+  Out( "pong\n" );
+  return 1;
+}
+
+
+static int
+cmd_hash( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+  long l;
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  if ( ! strcmp( str, "learn" ) )
+    {
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str != NULL && ! strcmp( str, str_on ) )
+       {
+         return hash_learn_on();
+       }
+      else if ( str != NULL && ! strcmp( str, str_off ) )
+       {
+         return hash_learn_off();
+       }
+#if ! defined(MINIMUM)
+      else if ( str != NULL && ! strcmp( str, "create" ) )
+       {
+         return hash_learn_create();
+       }
+#endif
+      else {
+       str_error = str_bad_cmdline;
+       return -2;
+      }
+    }
+
+  l = strtol( str, &ptr, 0 );
+  if ( ptr == str || l == LONG_MAX || l < 1 || l > 31 )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  
+  AbortDifficultCommand;
+  
+  log2_ntrans_table = (int)l;
+  memory_free( (void *)ptrans_table_orig );
+  return ini_trans_table();
+}
+
+
+static int
+cmd_limit( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+  long l1, l2, l3;
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  AbortDifficultCommand;
+
+  if ( ! strcmp( str, "depth" ) )
+    {
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      l1 = strtol( str, &ptr, 0 );
+      if ( ptr == str || l1 == LONG_MAX || l1 < 1 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      sec_limit_up = UINT_MAX;
+      node_limit   = UINT64_MAX;
+      depth_limit  = (int)l1;
+    }
+  else if ( ! strcmp( str, "nodes" ) )
+    {
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      l1 = strtol( str, &ptr, 0 );
+      if ( ptr == str || l1 == LONG_MAX || l1 < 1 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      sec_limit_up = UINT_MAX;
+      depth_limit  = PLY_MAX;
+      node_limit   = (uint64_t)l1;
+    }
+  else if ( ! strcmp( str, "time" ) )
+    {
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+
+      if ( ! strcmp( str, "extendable" ) )
+       {
+         game_status |= flag_time_extendable;
+       }
+      else if ( ! strcmp( str, "strict" ) )
+       {
+         game_status &= ~flag_time_extendable;
+       }
+      else {
+       l1 = strtol( str, &ptr, 0 );
+       if ( ptr == str || l1 == LONG_MAX || l1 < 0 )
+         {
+           str_error = str_bad_cmdline;
+           return -2;
+         }
+
+       str = strtok_r( NULL, str_delimiters, lasts );
+       if ( str == NULL )
+         {
+           str_error = str_bad_cmdline;
+           return -2;
+         }
+       l2 = strtol( str, &ptr, 0 );
+       if ( ptr == str || l2 == LONG_MAX || l2 < 0 )
+         {
+           str_error = str_bad_cmdline;
+           return -2;
+         }
+
+       str = strtok_r( NULL, str_delimiters, lasts );
+       if ( ! str ) { l3 = -1; }
+       else {
+         l3 = strtol( str, &ptr, 0 );
+         if ( ptr == str || l3 >= PLY_MAX || l3 < -1 )
+           {
+             str_error = str_bad_cmdline;
+             return -2;
+           }
+       }
+
+       if ( ! ( l1 | l2 ) ) { l2 = 1; }
+
+       depth_limit  = PLY_MAX;
+       node_limit   = UINT64_MAX;
+       sec_limit    = (unsigned int)l1 * 60U;
+       sec_limit_up = (unsigned int)l2;
+       if ( l3 == -1 ) { sec_limit_depth = UINT_MAX; }
+       else            { sec_limit_depth = (unsigned int)l3; }
+      }
+    }
+  else {
+    str_error = str_bad_cmdline;
+    return -2;
+  }
+
+  return 1;
+}
+
+
+static int
+cmd_read( tree_t * restrict ptree, char **lasts )
+{
+  const char *str1 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str3 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str_tmp;
+  FILE *pf_src, *pf_dest;
+  char str_file[SIZE_FILENAME];
+  char *ptr;
+  unsigned int moves;
+  long l;
+  int iret, flag, c;
+
+  flag    = flag_history | flag_rep | flag_detect_hang | flag_rejections;
+  moves   = UINT_MAX;
+  str_tmp = NULL;
+
+  if ( str1 == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  if ( str2 != NULL )
+    {
+      if ( ! strcmp( str2, "t" ) ) { flag |= flag_time; }
+      else if ( strcmp( str2, "nil" ) )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+    }
+
+  if ( str3 != NULL )
+    {
+      l = strtol( str3, &ptr, 0 );
+      if ( ptr == str3 || l == LONG_MAX || l < 1 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      moves = (unsigned int)l - 1U;
+    }
+
+  AbortDifficultCommand;
+
+  if ( ! strcmp( str1, "." ) )
+    {
+      str_tmp = "game.cs_";
+
+#if defined(NO_LOGGING)
+      strncpy( str_file, "game.csa", SIZE_FILENAME-1 );
+#else
+      snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
+               str_dir_logs, irecord_game );
+#endif
+      pf_dest = file_open( str_tmp, "w" );
+      if ( pf_dest == NULL ) { return -2; }
+
+      pf_src = file_open( str_file, "r" );
+      if ( pf_src == NULL )
+       {
+         file_close( pf_dest );
+         return -2;
+       }
+
+      while ( ( c = getc(pf_src) ) != EOF ) { putc( c, pf_dest ); }
+
+      iret = file_close( pf_src );
+      if ( iret < 0 )
+       {
+         file_close( pf_dest );
+         return iret;
+       }
+
+      iret = file_close( pf_dest );
+      if ( iret < 0 ) { return iret; }
+
+      flag |= flag_time;
+      str1  = str_tmp;
+    }
+
+  iret = read_record( ptree, str1, moves, flag );
+  if ( iret < 0 ) { return iret; }
+
+  iret = get_elapsed( &time_turn_start );
+  if ( iret < 0 ) { return iret; }
+
+  if ( str_tmp && remove( str_tmp ) )
+    {
+      out_warning( "remove() failed." );
+      return -2;
+    }
+
+  return 1;
+}
+
+
+static int
+cmd_resign( tree_t * restrict ptree, char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+  long l;
+
+  if ( str == NULL || *str == 'T' )
+    {
+      AbortDifficultCommand;
+
+      if ( game_status & mask_game_end ) { return 1; }
+
+#if defined(DEKUNOBOU)
+      if ( dek_ngame && record_game.moves < 2 )
+       {
+         str_error = "ignore resignation";
+         return -2;
+       }
+#endif
+
+      game_status |= flag_resigned;
+      renovate_time( root_turn );
+      out_CSA( ptree, &record_game, MOVE_RESIGN );
+    }
+  else {
+    l = strtol( str, &ptr, 0 );
+    if ( ptr == str || l == LONG_MAX || l < MT_CAP_PAWN )
+      {
+       str_error = str_bad_cmdline;
+       return -2;
+      }
+    resign_threshold = (int)l;
+  }
+
+  return 1;
+}
+
+
+static int
+cmd_move( tree_t * restrict ptree, char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  unsigned int move;
+  int iret;
+
+  if ( game_status & mask_game_end )
+    {
+      str_error = str_game_ended;
+      return -2;
+    }
+  
+  AbortDifficultCommand;
+
+  if ( str == NULL )
+    {
+      iret = get_elapsed( &time_turn_start );
+      if ( iret < 0 ) { return iret; }
+      
+      iret = com_turn_start( ptree, 0 );
+      if ( iret < 0 ) { return iret; }
+    }
+  else if ( ! strcmp( str, "restraint" ) )
+    {
+      iret = get_elapsed( &time_turn_start );
+      if ( iret < 0 ) { return iret; }
+      
+      iret = com_turn_start( ptree, flag_refer_rest );
+      if ( iret < 0 ) { return iret; }
+    }
+  else {
+
+    iret = interpret_CSA_move( ptree, &move, str );
+    if ( iret < 0 ) { return iret; }
+    
+    iret = get_elapsed( &time_turn_start );
+    if ( iret < 0 ) { return iret; }
+    
+#if defined(MNJ_LAN)
+    if ( sckt_mnj != SCKT_NULL )
+      {
+       const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+       char *ptr;
+       long l;
+       if ( str2 ) { l = strtol( str2, &ptr, 0 ); }
+       if ( ! str2 || ptr == str || l == LONG_MAX || l < 1 )
+         {
+           str_error = str_bad_cmdline;
+           return -2;
+         }
+       mnj_posi_id   = (int)l;
+       mnj_move_last = move;
+      }
+#endif
+
+    iret = make_move_root( ptree, move, ( flag_history | flag_time | flag_rep
+                                         | flag_detect_hang
+                                         | flag_rejections ) );
+    if ( iret < 0 ) { return iret; }
+  }
+  
+  return 1;
+}
+
+
+static int
+cmd_new( tree_t * restrict ptree, char **lasts )
+{
+  const char *str1 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+  const min_posi_t *pmp;
+  min_posi_t min_posi;
+  int iret;
+
+  AbortDifficultCommand;
+
+  if ( str1 != NULL )
+    {
+      memset( &min_posi.asquare, empty, nsquare );
+      min_posi.hand_black = min_posi.hand_white = 0;
+      iret = read_board_rep1( str1, &min_posi );
+      if ( iret < 0 ) { return iret; }
+
+      if ( str2 != NULL )
+       {
+         if      ( ! strcmp( str2, "-" ) ) { min_posi.turn_to_move = white; }
+         else if ( ! strcmp( str2, "+" ) ) { min_posi.turn_to_move = black; }
+         else {
+           str_error = str_bad_cmdline;
+           return -2;
+         }
+       }
+      else { min_posi.turn_to_move = black; }
+
+      pmp = &min_posi;
+    }
+  else { pmp = &min_posi_no_handicap; }
+
+  iret = ini_game( ptree, pmp, flag_history, NULL, NULL );
+  if ( iret < 0 ) { return iret; }
+
+  return get_elapsed( &time_turn_start );
+}
+
+
+static int
+cmd_problem( tree_t * restrict ptree, char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+  long l;
+  unsigned int nposition;
+  int iret;
+
+  if ( str != NULL )
+    {
+      l = strtol( str, &ptr, 0 );
+      if ( ptr == str || l == LONG_MAX || l < 1 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      nposition = (unsigned int)l;
+    }
+  else { nposition = UINT_MAX; }
+
+  AbortDifficultCommand;
+
+  iret = record_open( &record_problems, "problem.csa", mode_read, NULL, NULL );
+  if ( iret < 0 ) { return iret; }
+
+  iret = solve_problems( ptree, nposition );
+  if ( iret < 0 )
+    {
+      record_close( &record_problems );
+      return iret;
+    }
+
+  iret = record_close( &record_problems );
+  if ( iret < 0 ) { return iret; }
+
+  iret = ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL );
+  if ( iret < 0 ) { return iret; }
+
+  return get_elapsed( &time_turn_start );
+}
+
+
+static int
+cmd_quit( void )
+{
+  game_status |= flag_quit;
+  return 1;
+}
+
+
+static int
+cmd_suspend( void )
+{
+  if ( game_status & ( flag_pondering | flag_puzzling ) )
+    {
+      game_status |= flag_quit_ponder;
+      return 2;
+    }
+  
+  game_status |= flag_suspend;
+  return 1;
+}
+
+
+static int
+cmd_time( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  else if ( ! strcmp( str, "response" ) )
+    {
+      long l;
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      l = strtol( str, &ptr, 0 );
+      if ( ptr == str || l == LONG_MAX || l < 0 || l > 1000 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      time_response = (unsigned int)l;
+      return 1;
+    }
+  else if ( ! strcmp( str, "remain" ) )
+    {
+      long l1, l2;
+      
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      l1 = strtol( str, &ptr, 0 );
+      if ( ptr == str || l1 == LONG_MAX || l1 < 0 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      l2 = strtol( str, &ptr, 0 );
+      if ( ptr == str || l2 == LONG_MAX || l2 < 0 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+
+      if ( sec_limit_up == UINT_MAX )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+
+      return reset_time( (unsigned int)l1, (unsigned int)l2 );
+    }
+
+  str_error = str_bad_cmdline;
+  return -2;
+}
+
+
+#if !defined(MINIMUM)
+/* learn (ini|no-ini) steps games iterations tlp1 tlp2 */
+static int
+cmd_learn( tree_t * restrict ptree, char **lasts )
+{
+  const char *str1 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str3 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str4 = strtok_r( NULL, str_delimiters, lasts );
+#  if defined(TLP)
+  const char *str5 = strtok_r( NULL, str_delimiters, lasts );
+  const char *str6 = strtok_r( NULL, str_delimiters, lasts );
+#  endif
+  char *ptr;
+  long l;
+  unsigned int max_games;
+  int is_ini, nsteps, max_iterations, nworker1, nworker2, iret;
+
+  if ( str1 == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  if      ( ! strcmp( str1, "ini" ) )    { is_ini = 1; }
+  else if ( ! strcmp( str1, "no-ini" ) ) { is_ini = 0; }
+  else {
+    str_error = str_bad_cmdline;
+    return -2;
+  }
+
+  max_games      = UINT_MAX;
+  max_iterations = INT_MAX;
+  nworker1 = nworker2 = nsteps = 1;
+
+  if ( str2 != NULL )
+    {
+      l = strtol( str2, &ptr, 0 );
+      if ( ptr == str2 || l == LONG_MAX || l < 1 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      nsteps = (int)l;
+    }
+
+  if ( str3 != NULL )
+    {
+      l = strtol( str3, &ptr, 0 );
+      if ( ptr == str3 || l == LONG_MAX || l == LONG_MIN )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      if ( l > 0 ) { max_games = (unsigned int)l; }
+    }
+
+  if ( str4 != NULL )
+    {
+      l = strtol( str4, &ptr, 0 );
+      if ( ptr == str4 || l == LONG_MAX || l == LONG_MIN )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      if ( l > 0 ) { max_iterations = (int)l; }
+    }
+
+#  if defined(TLP)
+  if ( str5 != NULL )
+    {
+      l = strtol( str5, &ptr, 0 );
+      if ( ptr == str5 || l > TLP_MAX_THREADS || l < 1 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      nworker1 = (int)l;
+    }
+
+  if ( str6 != NULL )
+    {
+      l = strtol( str6, &ptr, 0 );
+      if ( ptr == str6 || l > TLP_MAX_THREADS || l < 1 )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      nworker2 = (int)l;
+    }
+#  endif
+
+  AbortDifficultCommand;
+
+  log2_ntrans_table = 12;
+
+  memory_free( (void *)ptrans_table_orig );
+
+  iret = ini_trans_table();
+  if ( iret < 0 ) { return iret; }
+
+  iret = learn( ptree, is_ini, nsteps, max_games, max_iterations,
+               nworker1, nworker2 );
+  if ( iret < 0 ) { return -1; }
+
+  iret = ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL );
+  if ( iret < 0 ) { return -1; }
+
+  iret = get_elapsed( &time_turn_start );
+  if ( iret < 0 ) { return iret; }
+
+  return 1;
+}
+#endif /* MINIMUM */
+
+
+#if defined(MPV)
+static int
+cmd_mpv( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+  long l;
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  else if ( ! strcmp( str, "num" ) )
+    {
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      l = strtol( str, &ptr, 0 );
+      if ( ptr == str || l == LONG_MAX || l < 1 || l > MPV_MAX_PV )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+
+      AbortDifficultCommand;
+
+      mpv_num = (int)l;
+
+      return 1;
+    }
+  else if ( ! strcmp( str, "width" ) )
+    {
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      l = strtol( str, &ptr, 0 );
+      if ( ptr == str || l == LONG_MAX || l < MT_CAP_PAWN )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+
+      AbortDifficultCommand;
+
+      mpv_width = (int)l;
+
+      return 1;
+    }
+
+  str_error = str_bad_cmdline;
+  return -2;
+}
+#endif
+
+
+#if defined(TLP)
+static int
+cmd_thread( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  else if ( ! strcmp( str, "num" ) )
+    {
+      char *ptr;
+      long l;
+
+      str = strtok_r( NULL, str_delimiters, lasts );
+      if ( str == NULL )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+      l = strtol( str, &ptr, 0 );
+      if ( ptr == str || l == LONG_MAX || l < 1 || l > TLP_MAX_THREADS )
+       {
+         str_error = str_bad_cmdline;
+         return -2;
+       }
+
+      TlpEnd();
+
+      tlp_max = (int)l;
+
+      if ( game_status & ( flag_thinking | flag_pondering | flag_puzzling ) )
+       {
+         return tlp_start();
+       }
+      return 1;
+    }
+
+  str_error = str_bad_cmdline;
+  return -2;
+}
+#endif
+
+
+#if defined(CSA_LAN)
+static int
+cmd_connect( tree_t * restrict ptree, char **lasts )
+{
+  const char *str;
+  char *ptr;
+  long max_games;
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str || ! strcmp( str, "." ) ) { str = "gserver.computer-shogi.org"; }
+  strncpy( client_str_addr, str, 255 );
+  client_str_addr[255] = '\0';
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str || ! strcmp( str, "." ) ) { str = "4081"; }
+  client_port = strtol( str, &ptr, 0 );
+  if ( ptr == str || client_port == LONG_MAX || client_port < 0
+       || client_port > USHRT_MAX )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza_test"; }
+  strncpy( client_str_id, str, 255 );
+  client_str_id[255] = '\0';
+
+  str = strtok_r( NULL, " \t", lasts );
+  if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza_test"; }
+  strncpy( client_str_pwd, str, 255 );
+  client_str_pwd[255] = '\0';
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str || ! strcmp( str, "." ) ) { client_max_game = INT_MAX; }
+  else {
+    max_games = strtol( str, &ptr, 0 );
+    if ( ptr == str || max_games == LONG_MAX || max_games < 1 )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+    client_max_game = max_games;
+  }
+
+  AbortDifficultCommand;
+
+  client_ngame          = 0;
+
+  return client_next_game( ptree, client_str_addr, (int)client_port );
+}
+#endif
+
+
+#if defined(MNJ_LAN)
+static int
+cmd_mnj( tree_t * restrict ptree, char **lasts )
+{
+  char client_str_addr[256];
+  char client_str_id[256];
+  const char *str;
+  char *ptr;
+  unsigned int seed;
+  int sd;
+  long l;
+  int client_port;
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  l = strtol( str, &ptr, 0 );
+  if ( ptr == str || l == LONG_MAX || l < 0 )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  sd = (int)l;
+
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  l = strtol( str, &ptr, 0 );
+  if ( ptr == str || l == LONG_MAX || l < 0 )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  seed = (unsigned int)l;
+
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str || ! strcmp( str, "." ) ) { str = "localhost"; }
+  strncpy( client_str_addr, str, 255 );
+  client_str_addr[255] = '\0';
+
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str || ! strcmp( str, "." ) ) { str = "4082"; }
+  l = strtol( str, &ptr, 0 );
+  if ( ptr == str || l == LONG_MAX || l < 0 || l > USHRT_MAX )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  client_port = (int)l;
+
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza1"; }
+  strncpy( client_str_id, str, 255 );
+  client_str_id[255] = '\0';
+
+  AbortDifficultCommand;
+
+  resign_threshold  = 65535;
+  game_status      |= ( flag_noponder | flag_noprompt );
+  if ( mnj_reset_tbl( sd, seed ) < 0 ) { return -1; }
+
+  sckt_mnj = sckt_connect( client_str_addr, (int)client_port );
+  if ( sckt_mnj == SCKT_NULL ) { return -2; }
+
+  str_buffer_cmdline[0] = '\0';
+
+  Out( "Sending my name %s", client_str_id );
+  sckt_out( sckt_mnj, "%s\n", client_str_id );
+
+  return analyze( ptree );
+}
+#endif
+
+
+#if defined(DEKUNOBOU)
+
+static int
+cmd_dek( char **lasts )
+{
+  const char *str = strtok_r( NULL, str_delimiters, lasts );
+  char *ptr;
+  long l1, l2;
+  int iret;
+
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  strncpy( str_message, str, SIZE_MESSAGE-1 );
+  str_message[SIZE_MESSAGE-1] = '\0';
+  dek_ul_addr = inet_addr( str );
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  l1 = strtol( str, &ptr, 0 );
+  if ( ptr == str || l1 == LONG_MAX || l1 < 0 || l1 > USHRT_MAX )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  str = strtok_r( NULL, str_delimiters, lasts );
+  if ( str == NULL )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+  l2 = strtol( str, &ptr, 0 );
+  if ( ptr == str || l2 == LONG_MAX || l2 < 0 || l2 > USHRT_MAX )
+    {
+      str_error = str_bad_cmdline;
+      return -2;
+    }
+
+  AbortDifficultCommand;
+
+  iret = dek_start( str_message, (int)l1, (int)l2 );
+  if ( iret < 0 ) { return iret; }
+
+  Out( "\n- in communication with Dekunobou...\n" );
+
+  str_buffer_cmdline[0] = '\0';
+  dek_ngame    = 1;
+  dek_lost     = 0;
+  dek_win      = 0;
+  dek_turn     = 1;
+  game_status |= flag_resigned;
+  
+  return 1;
+}
+
+#endif
+
diff --git a/quiesrch.c b/quiesrch.c
new file mode 100644 (file)
index 0000000..6ceb5fb
--- /dev/null
@@ -0,0 +1,222 @@
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include "shogi.h"
+
+/* #define DBG_QSEARCH */
+#if defined(DBG_QSEARCH)
+#  define DOut( ... )  if ( dbg_flag ) { out( __VA_ARGS__ ); }
+#else
+#  define DOut( ... )
+#endif
+
+static int gen_next_quies( tree_t * restrict ptree, int alpha, int turn,
+                          int ply, int qui_ply );
+
+int
+search_quies( tree_t * restrict ptree, int alpha, int beta, int turn, int ply,
+             int qui_ply )
+{
+  int value, alpha_old;
+
+#if defined(DBG_QSEARCH)
+  int dbg_flag = 0;
+
+  if ( iteration_depth == 2 && ply == 4
+       && ! strcmp( str_CSA_move(ptree->current_move[1]), "7776FU" )
+       && ! strcmp( str_CSA_move(ptree->current_move[2]), "3334FU" )
+       && ! strcmp( str_CSA_move(ptree->current_move[3]), "8822UM" ) )
+    {
+      dbg_flag = 1;
+      Out( "qsearch start (alpha=%d beta=%d sp=%d %" PRIu64 ")",
+          alpha, beta, value, ptree->node_searched );
+    }
+#endif
+  
+
+#if defined(TLP)
+  if ( ! ptree->tlp_id )
+#endif
+    {
+      node_last_check += 1;
+    }
+  ptree->node_searched += 1;
+  ptree->nquies_called += 1;
+  alpha_old             = alpha;
+  
+  value = evaluate( ptree, ply, turn );
+
+
+  if ( alpha < value )
+    {
+      if ( beta <= value )
+       {
+         DOut( ", cut by stand-pat\n" );
+         MOVE_CURR = MOVE_PASS;
+         return value;
+       }
+      alpha = value;
+    }
+
+  if ( ply >= PLY_MAX-1 )
+    {
+      if ( alpha_old != alpha ) { pv_close( ptree, ply, no_rep ); }
+      MOVE_CURR = MOVE_NA;
+      return value;
+    }
+
+
+  if ( ( qui_ply == 1 && ! ( ply == 2 && InCheck( turn ) ) )
+       || ( 1 < qui_ply && qui_ply < QUIES_PLY_LIMIT && ! InCheck( turn ) ) )
+    {
+      MOVE_CURR = IsMateIn1Ply( turn );
+      if ( MOVE_CURR )
+       {
+         value = score_mate1ply + 1 - ply;
+
+         if ( alpha < value
+              && value < beta ) { pv_close( ptree, ply, mate_search ); }
+
+         DOut( "mate found\n" );
+
+         assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+         return value;
+       }
+    }
+
+
+  ptree->anext_move[ply].next_phase = next_quies_gencap;
+  while ( gen_next_quies( ptree, alpha, turn, ply, qui_ply ) )
+    {
+      DOut( "\nexpand %s (%" PRIu64 ")",
+           str_CSA_move(MOVE_CURR), ptree->node_searched );
+
+      MakeMove( turn, MOVE_CURR, ply );
+      if ( InCheck(turn) )
+       {
+         UnMakeMove( turn, MOVE_CURR, ply );
+         continue;
+       }
+
+      value = -search_quies( ptree, -beta, -alpha, Flip(turn), ply+1,
+                            qui_ply+1 );
+
+      UnMakeMove( turn, MOVE_CURR, ply );
+
+      if ( alpha < value )
+       {
+         check_futile_score_quies( ptree, MOVE_CURR, ptree->stand_pat[ply],
+                                   -ptree->stand_pat[ply+1], turn );
+         if ( beta <= value )
+           {
+             DOut( ", beta cut (%" PRIu64 ")\n", ptree->node_searched );
+
+             assert( ! IsMove(MOVE_CURR)
+                     || is_move_valid( ptree, MOVE_CURR, turn ) );
+             return value;
+           }
+
+         DOut( ", renew alpha=%d (%" PRIu64 ")\n",
+               value, ptree->node_searched );
+         alpha = value;
+       }
+    }
+
+  DOut( "\nall searched (%" PRIu64 ")\n", ptree->node_searched );
+
+  if ( qui_ply < QUIES_PLY_LIMIT && is_mate_in3ply( ptree, turn, ply ) )
+    {
+      value = score_mate1ply + 1 - ply;
+      
+      if ( alpha < value
+          && value < beta ) { pv_close( ptree, ply, mate_search ); }
+
+      assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+      return value;
+    }
+
+  if ( alpha_old != alpha )
+    {
+      if ( alpha == ptree->stand_pat[ply] ) { pv_close( ptree, ply, no_rep ); }
+      else { pv_copy( ptree, ply ); }
+    }
+
+  return alpha;
+}
+
+
+static int
+gen_next_quies( tree_t * restrict ptree, int alpha, int turn, int ply,
+               int qui_ply )
+{
+  switch ( ptree->anext_move[ply].next_phase )
+    {
+    case next_quies_gencap:
+      { 
+       unsigned int * restrict pmove;
+       int * restrict psortv;
+       int i, j, n, nqmove, value, min_score, diff;
+       unsigned int move;
+         
+       ptree->move_last[ply] = GenCaptures( turn, ptree->move_last[ply-1] );
+
+       /* set sort values */
+       pmove  = ptree->move_last[ply-1];
+       psortv = ptree->sort_value;
+       nqmove = 0;
+       n      = (int)( ptree->move_last[ply] - pmove );
+       
+       for ( i = 0; i < n; i++ )
+         {
+           move = pmove[i];
+
+           if ( qui_ply >= QUIES_PLY_LIMIT
+                && ( ( UToCap(move) == pawn && ! I2IsPromote(move) )
+                     || ( ! UToCap(move) && I2PieceMove(move) != pawn ) ) )
+             {
+               continue;
+             }
+
+           diff      = estimate_score_diff( ptree, move, turn );
+           min_score = eval_max_score( ptree, move, ptree->stand_pat[ply],
+                                       turn, diff );
+
+           if ( alpha < min_score )
+             {
+               value = swap( ptree, move, -1, MT_CAP_SILVER, turn );
+               if ( -1 < value )
+                 {
+                   psortv[nqmove]  = value + diff;
+                   pmove[nqmove++] = move;
+                 }
+             }
+         }
+       
+       /* insertion sort */
+       psortv[nqmove] = INT_MIN;
+       for ( i = nqmove-2; i >= 0; i-- )
+         {
+           value = psortv[i];  move = pmove[i];
+           for ( j = i+1; psortv[j] > value; j++ )
+             {
+               psortv[j-1] = psortv[j];  pmove[j-1] = pmove[j];
+             }
+           psortv[j-1] = value;  pmove[j-1] = move;
+         }
+
+       ptree->move_last[ply]             = ptree->move_last[ply-1] + nqmove;
+       ptree->anext_move[ply].move_last  = pmove;
+       ptree->anext_move[ply].next_phase = next_quies_captures;
+      }
+      
+    case next_quies_captures:
+      if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+       {
+         MOVE_CURR = *ptree->anext_move[ply].move_last++;
+         return 1;
+       }
+    }
+
+  return 0;
+}
diff --git a/rand.c b/rand.c
new file mode 100644 (file)
index 0000000..2974cd0
--- /dev/null
+++ b/rand.c
@@ -0,0 +1,90 @@
+#include "shogi.h"
+
+/* PRNG based on Mersenne Twister (M. Matsumoto and T. Nishimura, 1998). */
+#define RAND_M 397
+#define MASK_U 0x80000000U
+#define MASK_L 0x7fffffffU
+#define MASK32 0xffffffffU
+
+void
+ini_rand( unsigned int u )
+{
+  int i;
+
+  rand_work.count   = RAND_N;
+  rand_work.cnst[0] = 0;
+  rand_work.cnst[1] = 0x9908b0dfU;
+
+  u &= MASK32;
+  rand_work.vec[0] = u;
+  for ( i = 1; i < RAND_N; i++ ) 
+    {
+      u  = i + 1812433253U * ( u ^ ( u >> 30 ) );
+      u &= MASK32;
+      rand_work.vec[i] = u;
+    }
+}
+
+
+unsigned int
+rand32( void )
+{
+  unsigned int u, u0, u1, u2;
+  int i;
+
+  if ( rand_work.count == RAND_N )
+    {
+      rand_work.count = 0;
+
+      for ( i = 0; i < RAND_N-RAND_M; i++ )
+       {
+         u  = rand_work.vec[i]   & MASK_U;
+         u |= rand_work.vec[i+1] & MASK_L;
+         
+         u0 = rand_work.vec[ i + RAND_M ];
+         u1 = u >> 1;
+         u2 = rand_work.cnst[ u & 1 ];
+
+         rand_work.vec[i] = u0 ^ u1 ^ u2;
+       }
+         
+      for ( ; i < RAND_N-1 ;i++ )
+       {
+         u  = rand_work.vec[i]   & MASK_U;
+         u |= rand_work.vec[i+1] & MASK_L;
+
+         u0 = rand_work.vec[ i + RAND_M - RAND_N ];
+         u1 = u >> 1;
+         u2 = rand_work.cnst[ u & 1 ];
+
+         rand_work.vec[i] = u0 ^ u1 ^ u2;
+        }
+
+      u  = rand_work.vec[RAND_N-1] & MASK_U;
+      u |= rand_work.vec[0]        & MASK_L;
+
+      u0 = rand_work.vec[ RAND_M - 1 ];
+      u1 = u >> 1;
+      u2 = rand_work.cnst[ u & 1 ];
+
+      rand_work.vec[RAND_N-1] = u0 ^ u1 ^ u2;
+    }
+  
+  u  = rand_work.vec[ rand_work.count++ ];
+  u ^= ( u >> 11 );
+  u ^= ( u <<  7 ) & 0x9d2c5680U;
+  u ^= ( u << 15 ) & 0xefc60000U;
+  u ^= ( u >> 18 );
+
+  return u;
+}
+
+
+uint64_t
+rand64( void )
+{
+  uint64_t h = rand32();
+  uint64_t l = rand32();
+
+  return l | ( h << 32 );
+}
diff --git a/readme.txt b/readme.txt
new file mode 100644 (file)
index 0000000..7aaf0fb
--- /dev/null
@@ -0,0 +1,562 @@
+----------------------------------------------------------------------
+              Bonanza Feliz 0.0 - Executable Source Code
+                                            Kunihito Hoki, 1 Apr 2010
+----------------------------------------------------------------------
+
+
+1. Introduction
+----------------
+
+Bonanza is a state-of-the art computer shogi engine which runs on
+Windows and Linux machines, and this directory contains a
+platform-independent source code.
+
+This source code is distributed with a hope that it will be useful in
+addition to the main part of the shogi engine. This program includes
+many useful functions such as manipulating a shogi board, reading and
+writing a CSA record file, speaking of a CSA protocol with a socket
+communication, and controlling time, and etc.. I believe this program
+can be a good starting point if you are interested in making shogi
+programs.
+
+One main feature of this program is that it employs a brute-force
+search method together with bitboard techniques as many chess programs
+do. Another notable feature is a machine learning of shogi evaluation
+functions. The details of the learning algorithm (aka Bonanza method)
+were already presented [1], and this source code provides an example
+of implementation of the learning method.
+
+I admit that some parts of the source code are cryptic, e.g. codes in
+"mate1ply.c". I hope that I will have some time to make a quality
+documentation and comments on the program code, or someone else could
+decrypt my program and provide a documentation.
+
+Any comments or suggestions are welcome [2].
+
+[1] K. Hoki, "Optimal control of minimax search results to learn
+    positional evaluation", Game Programming Workshop, Hakone, Japan
+    2008.
+
+[2] Contact to "bonanza_query [at] hotmail.com".
+
+
+2. Legal Notices
+-----------------
+
+This program is protected by copyright. Without a specific 
+permission, any means of commercial applications are prohibited.
+Furthermore, this program is distributed without any warranty.
+Within these limits, you can use, redistribute, and/or modify it.
+
+
+3. Change Logs
+---------------
+
+Feliz 0.0
+
+- Some results from Y. Sato's experiments with Bonanza inspired me
+  to use the history table in LMR in Shogi, as Fruit did in chess. By
+  doing so, some improvement in performance of the tree search is
+  made.
+
+- From private communications with Yaneurao, it turned out that the
+  3-ply-mate detections in 'mate3.c' can search game trees more
+  efficiently by using several heuristic pruning techniques. Now
+  'mate3.c' adopts some of these techniques.
+
+- E. Ito kindly reported two bugs in the source codes. One is in
+  hash_store(), and the other is in ehash_probe() and
+  ehash_store(). Now these are fixed.
+
+- The structure of history table is modified from 'square-to' and
+  'square-from' method to an exact match method by using the perfect
+  hash technique. The hash function of moves in 'phash.c' is generated
+  by codes at http://burtleburtle.net/bob/hash/perfect.html.
+
+- A command 'mnj' is added to connect to the cluster-computing server
+  in src/cluster/.
+
+- In client_next_game(), the way of dealing with REJECT message from a
+  CSA Shogi server is revised. Now Bonanza connects to the server again
+  when the game is rejected by an opponent.
+
+
+Version 4.1.3
+- The owner of 'LS3600 Blog Webpage' pointed out that there were two
+  serious bugs. Thank you very much! According to his indication,
+  is_hand_eq_supe() in 'utility.c' and read_CSA_line() in 'csa.c' are
+  revised.
+- In MPV code in 'searchr.c', a test of 'root_abort' flag had been
+  forgotten. Now the flag is tested after every call of search().
+- 'lan.txt' is added to 'src/executable/' directory. This is an
+  example of an input sequence to connect to CSA Shogi server.
+- 'book.bin' now has smaller moves and positions than previous one does.
+  Also, 'book_anti.csa' is added to 'src/executable/' directory. This
+  is an example of bad moves which apear in records of human experts.
+- 'Legal Notices' in this document is corrected.
+
+Version 4.1.2
+- In 'Makefile' and 'Makefile.vs', targets which require profile-guided
+  optimization are removed. Furthermore, an option, which controls
+  optimization, has been reverted from the aggressive flag, -O3, to a
+  moderate one, '-O2'. These modifications were necessary for avoiding
+  abnormal terminations of the program.
+- In 'ini.c', the attribute of POSIX thread in a global-variable
+  'pthread_attr' is set to 'detach-state'. Because threads will never
+  join with any other threads in this program, the thread should be
+  created in the detached state to free system resources.
+- In 'ini.c', the default size of the transposition table is lifted
+  from 12MByte to 48MByte.
+- In 'iterate.c", probing the opening book is avoided when the move
+  history of a current game has repetitions.
+- In 'shogi.h', the margins of futility pruning are increased in
+  accord with new positional evaluation of the feature vector in
+  'fv.bin'.
+- The quality of an opening book, 'winbin/book.bin', has been improved
+  at the expense of quantity.
+
+Version 4.1.0 and 4.1.1 (26 Apr 2009)
+- In 'Makefile' and 'Makefile.vs', some options of Intel C compiler
+  are modified. Here, agressive optimization '-O3' is substituted for
+  the default '-O2', pthreads support '-pthread' is substituted for
+  '-lpthread', and an obsolete '-static-libcxx' is removed.
+- In 'Makefile', the conformance of GNU C and Intel C compilers are
+  set to GNU extensions of ISO C99 by setting '-std=gnu99' because a
+  POSIX function 'strtok_r()' is not in the C99 standard library.
+- In 'Makefile', targets for GNU C with gprof and profile-guided
+  optimization of GNU C are removed.
+- In 'shogi.h', inline assemblies and intrinsics are used on x86-64 as
+  well as x86. To detect the targets, pre-defined macros '__i386__'
+  and '__x86_64__' are examined.
+- In 'evaluate.c', the evaluation function looks up the table
+  'stand_pat[ply]' to see if the position have been evaluated since
+  the previous move is made by 'make_move_[bw]()' functions. Also, the
+  evaluation function probes the hash table 'ehash_tbl[]' to avoid
+  re-evaluation of the same position.
+- In 'io.c', an immediate value 0 is substituted for 'fileno(stdin)'
+  because the POSIX function 'fileno()' is not part of ANSI C. POSIX
+  requires that the file descriptor associated with 'stdin' be 0.
+- In 'iterate.c', a criterion for aging of transposition-table, i.e.,
+  increment of a global variable 'trans_table_age', is lifted from 7%
+  to 9% of saturation ratio of the table.
+- In 'learn1.c', the macro 'SEARCH_DEPTH' is set to 2. The macro
+  specifies the depth threashold of searches for finding all of
+  principle variations of positions in a set of games.
+- In 'learn1.c', a step size of increment/decrement of feature vectors
+  is fixed to 1 in 'learn_parse2()' function.
+- In 'hash.c', when a node can be pruned by using a hash value based on
+  futility pruning, a return value of the node is set to beta.
+- In 'rand.c', some codes of initialization of PRNG variables are
+  moved to 'ini_genrand()' from 'ini()' function.
+- In 'sckt.c', a function 'send_crlf()' is removed.
+- In 'search.c', now 'search()' calls 'search_quies()' and returns if
+  a search depth reaches a threashold. So that we can call 'search()'
+  function anytime, and this makes source codes simple.
+- In 'search.c', the static evaluation value is evaluated and used to
+  see if the late-move reduction is applicable or not. The evaluation
+  value is also used by the futility pruning.
+- In 'search.c', the futility pruning is not applied if the node is in
+  check or the move is a check.
+- In 'search.c', now Bonanza sends the keep-alive command '0x0a' to
+  the server in 'detect_signals()'.
+- In 'time.c', 'set_seach_limit_time()' is simplified.
+- In 'time.c', the second argument of 'gettimeofday()' is set to 'NULL'.
+
+Version 4.0.4 (2 Feb 2009)
+- An error of GCC inline assembly for spinlock in "thread.c" is fixed.
+- In Windows OS, Bonanza now opens all streams with file sharing by
+  using "_SH_DENYNO" constant in "io.c".
+- GCC built-in functions are substituted for GCC inline assemblies for
+  bit-scan operations in "bitop.h". Furthermore, "bitop.h" is removed,
+  and some of macros in the header are integrated into "shogi.h".
+
+Version 4.0.3 (Jan 2008)
+
+
+4. Files
+---------
+
+Here is a list of files you can find in this directory.
+
+C headers
+- param.h     piece values
+- shogi.h     main header
+
+basic C functions
+- main.c      main function of C program
+- data.c      definition of global variables
+- ini.c       initializations
+- rand.c      pseudo random number generator
+- time.c      time functions
+- bitop.c     bit operation
+- utility.c   misc. functions
+
+I/O
+- proce.c     input procedure 
+- csa.c       csa file format I/O
+- io.c        basic I/O
+- dek.c       dekunobou
+- sckt.c      TCP/IP client of CSA SHOGI protocol
+
+bitboard manipulations
+- attack.c    piece attacks
+- genchk.c    move generation (checks)
+- genevasn.c  move generation (evasions)
+- gendrop.c   move generation (drops)
+- gennocap.c  move generation (non-captures)
+- gencap.c    move generation (captures)
+- movgenex.c  move generation (inferior moves)
+- makemove.c  make moves
+- unmake.c    unmake move
+- mate1ply.c  1-ply mate detection
+- debug.c     examine bitboard validity
+
+brute-force search
+- iterate.c   iterative deepning search at root node
+- searchr.c   alpha-beta search at root node
+- search.c    alpha-beta search
+- next.c      obtains next move
+- quiesrch.c  quiescence search
+- evaluate.c  static eveluation function
+- evaldiff.c  easy and fast evaluation function
+- swap.c      static exchange evaluation
+- hash.c      transposition table
+- thread.c    thread-level parallelization
+- root.c      root move genelation and shallow min-max search
+- mate3.c     3-ply mate detection
+- ponder.c    pondering
+- book.c      creates and probes opening book
+- problem.c   auto problem solver
+- valid.c     examine move validity
+
+optimal control of min-max search
+- learn1.c    main functions
+- learn2.c    feture vector manipuration
+
+misc.
+- bonanza.txt which now you are looking at
+- Makefile    makefile for gnu make.exe
+- Makefile.vs makefile for Microsoft nmake.exe
+- bonanza.ico icon file for windows
+- bonanza.rc  resource-definition file for windows
+- lan.txt     example of input sequence to connect CSA Shogi server
+- book_anti.csa example of a set of bad moves which apear in records
+              of human exparts. This is used by 'book create' command.
+
+4. How to build Bonanza
+-----------------------
+
+You can build Bonanza by means of GNU Make on Linux or Microsoft NMAKE
+on Windows. Here is some examples:
+
+- GCC on Linux
+> make -f Makefile gcc
+
+- Intel C++ Compiler on Linux
+> make -f Makefile icc
+
+- Microsoft C/C++ Compiler on Windows
+> nmake -f Makefile.vs cl
+
+- Intel C++ Compiler on Windows
+> nmake -f Makefile.vs icl
+
+The C source codes are written by using ANSI C plus a small number of
+new features in ISO C99. Therefore, I think this can be easily built
+in many platforms without much effort.
+
+It may be necessary to define some macros in Makefile or
+Makefile.vs. The macros are:
+
+- NDEBUG (DEBUG)    builds release (debug) version of Bonanza
+
+- MINIMUM           disables some auxiliary functions that are not
+                    necessary to play a game, e.g., book composition
+                    and optimization of evaluation functions
+
+- TLP               enables thread-level parallel search
+
+- MPV               enables multi-PV search
+
+- CSA_LAN           enables Bonanza to communicate by CSA Shogi TCP/IP
+                    protcol
+
+- DEKUNOBOU         enables dekunobou interface (available only for
+                    Windows)
+
+- CSASHOGI          builds an engine for CSA Shogi (available only for
+                    Windows)
+
+- NO_LOGGING        suppresses dumping log files
+
+Bonanza is an application that does not provide graphical user
+interface. If you could build "bonanza.exe" properly without CSASHOGI
+macro, it shows a prompt "Black 1>" when you execute it at a computer
+console.
+
+Bonanza uses three binary files: a feature vector of static evaluation
+function "fv.bin",  an opening book "book.bin", and a
+position-learning database "hash.bin". You can find these in "winbin/"
+directory. Without the NO_LOGGING option, Bonanza must find "log/"
+directory to dump log files.
+
+
+5. Command List
+---------------
+
+- beep on
+- beep off
+    These commands enable (on) or disable (off) a beep when Bonanza
+    makes a move.  The default is on.
+
+- book on
+- book off
+    These commands enable (on) or disable (off) to probe the opening
+    book, "./book.bin".  The default is on.
+
+- book narrow
+- book wide
+    When the command with "narrow" is used, Bonanza selects a book
+    move from a small set of opening moves. The default is "wide". The
+    narrowing of the opening moves is useful if you want Bonanza
+    choose a common opening line.
+
+- book create
+    This command creates the opening book file, "./book.bin", by using
+    numerous experts' games in a single CSA record file, "./book.csa".
+    It also uses another CSA record file, "book_anti.csa", where you
+    can register bad moves that may appear in the experts' games at
+    the last moves in the record file. Here is the example:
+
+    ----------------------------------------
+    PI, +, +6978KI, %TORYO
+    /
+    PI, +, +6978KI, -8384FU, %TORYO
+    /
+    PI, +, +7776FU, -4132KI, %TORYO
+    /
+    PI, +, +7776FU, -4132KI, +2726FU, %TORYO
+    ----------------------------------------
+
+    This command becomes effective when MINIMUM macro is not defined
+    in the Makefile.
+
+- connect 'addr' 'port' 'id' 'passwd' ['ngame']
+    This command connects Bonanza to a shogi server by using the CSA
+    protocol. The first four arguments specify the network address,
+    port number, user ID, and password, respectively. The last
+    argument limits a number of games that will be played by Bonanza.
+    This command becomes effective when CSA_LAN macro is defined in
+    the Makefile.
+
+- dekunobou 'addr' 'port-dekunobou' 'port-bonanza'
+    This command connects Bonanza to Dekunobou.
+
+- display ['num']
+    This command prints the shogi board. If you want to flip the
+    board, set 'num' to 2. If not, set it to 1.
+
+- s
+    Bonanza makes a prompt reply while thinking as soon as this
+    command is used.
+
+- hash 'num'
+    This command is used to initialize the transposition table and
+    set the size of the table to 2^'num'.
+
+- hash learn create
+    This command is used to make a zero-filled position-lerning
+    database, "hash.bin". This command becomes effective when MINIMUM
+    macro is not defined in the Makefile.
+
+- hash learn on
+- hash learn off
+    These commands enable (on) or disable (off) the position learning.
+    The default is on.
+
+- learn 'str' 'steps' ['games' ['iterations' ['num1' ['num2']]]]
+    This command optimizes a feature vector of the static evaluation
+    function by using numorous experts' games in a single CSA record
+    file, "./records.csa". If you want to use a zero-filled vector as
+    an initial guess of the optimization procedure, set 'str' to
+    "ini". If not, set it to "no-ini". The third argument 'games' is a
+    number of games to be read from the record file. If the third
+    argument is negative or omitted, all games are read from the file.
+
+    The learning method iterates a set of procedures, and the number
+    of iteration can be limited by the fourth argument. It continues
+    as long as the argument is negative. The procedures consist of two
+    parts. The first part reads the record file and creates principal
+    variations by using 'num1' threads. The default value of 'num1' is
+    1. The second part renews the feature vector 'steps' times by using
+    'num2' threads in accord with the principal variations. The default
+    value of 'steps' and 'num2' is 1. Note that each thread in the
+    second procedure uses about 500MByte of the main memory. The two
+    arguments 'num1' and 'num2' become effective when TLP macro is
+    defined in the Makefile. After the procedures, the optimized
+    vector is saved in "./fv.bin". This command become effective when
+    MINIMUM macro is not defined in the Makefile.
+
+- limit depth 'num'
+    This command is used to specify a depth, 'num', at which Bonanza
+    ends the iterative deepening search.
+
+- limit nodes 'num'
+    When this command is used, Bonanza stops thinking after searched
+    nodes reach to 'num'.
+
+- limit time 'minute' 'second' ['depth']
+    This command limits thinking time of Bonanza. It tries to make
+    each move by consuming the time 'minute'. When the time is spent
+    all, it makes each move in 'second'. The last argument 'depth' can
+    be used if you want Bonanza to stop thinking after the iterative
+    deepening searches reach sufficient depth.
+
+- limit time extendable
+- limit time strict
+    The command, "limit time extendable", allows Bonanza to think
+    longer than the time limited by the previous command if it wishes
+    to. The default is "strict".
+
+- mnj 'sd' 'seed' 'addr' 'port' 'id'
+    This command connects Bonanza to the council server in
+    src/cluster/. The first two integers specify the standard
+    deviation and initial seed of pseudo-random numbers which are
+    added to the static evaluation function. Experiments suggested
+    that an appropriate value for the standard deviation is 50. Note
+    that all clients should use different seeds. The last three
+    arguments are network address, port number, user ID,
+    respectively. This command becomes effective when MNJ_LAN macro is
+    defined in the Makefile.
+
+- move ['str']
+    Bonanza makes a move of 'str'. If the argument is omitted, Bonanza
+    thinks of its next move by itself.
+
+- mpv num 'nroot'
+- mpv width 'threshold'
+    These commands control the number of root moves, 'nroot', to
+    constitute principal variations. The default number is 1. A root
+    move that yields a smaller value than the best value by 'threshold'
+    is neglected. The default threshold is about 200. These commands
+    become effective when MPV macro is defined in the Makefile.
+
+- new ['str']
+    This command initializes the shogi board. The argument 'str'
+    controls an initial configuration of the board.  If you want to
+    play a no-handicapped game, set 'str' to "PI" and this is the
+    default value. In a handicapped game, specify squares and pieces
+    to drop, e.g. "new PI82HI22KA" or "new PI19KY".
+
+- peek on
+- peek off
+    The command "peek on (off)" enables (disables) peeks at a buffer
+    of the standard input file while Bonanza is thinking. The default
+    is on. This command is useful when you want to process a set of
+    commands as "> ./bonanza.exe < infile".
+
+- ping
+    Prompt Bonanza to print "pong".
+
+- ponder on
+- ponder off
+    The command "ponder on (off)" enables (disables) thinks on the
+    opponent's time. The default is on.
+
+- problem ['num']
+    This command is used to solve problems in "./problem.csa". Here
+    is an example of the problem file.
+
+    -----------------------------
+    $ANSWER:+0024FU
+    P1-KY-KE-OU-KI *  *  *  * -KY
+    P2 *  *  *  *  * -KI *  *  * 
+    P3 *  * -FU-GI-FU * -KE * -KA
+    P4-FU *  * -FU-GI-FU-HI * -FU
+    P5 *  *  *  *  *  *  * -FU+KY
+    P6+FU+KA+FU+FU+GI+FU+KI *  * 
+    P7 * +FU *  * +FU *  *  *  * 
+    P8 * +OU+KI+GI *  * +HI *  * 
+    P9+KY+KE *  *  *  *  * +KE * 
+    P+00FU00FU
+    P-00FU00FU00FU
+    +
+    /
+    $ANSWER:+0087KY:+0088KY
+    P1-OU-KE *  *  *  *  * +GI * 
+    P2-KY-KI *  *  *  *  *  *  * 
+    P3-FU-HI * -KI *  * -GI *  * 
+    P4 *  * -KE *  *  *  *  * -FU
+    P5 * +GI * -FU-FU-FU-FU-FU * 
+    P6+FU+HI-FU *  *  *  *  *  * 
+    P7 *  *  * +FU *  *  *  * +FU
+    P8 *  * +OU+KI+KI *  *  *  * 
+    P9+KY+KE *  *  *  *  * +KE+KY
+    P+00KA00GI00KY00FU00FU
+    P-00KA00FU00FU00FU00FU00FU
+    +
+    -----------------------------
+
+    The argument 'num' specifies the number of problems to solve.
+
+- quit
+    The quit command and EOF character will exit Bonanza.
+
+- read 'filename' [(t|nil) ['num']]
+    This command is used to read a CSA record 'filename' up to 'num'
+    moves. Set the second argument to "nil" when you want to ignore
+    time information in the record. The default value is "t". Bonanza
+    reads all move sequence if the last argument is neglected. If
+    'filename' is ".", the command reads an ongoing game from the
+    initial position.
+
+- resign
+    Use this command when you resign a game.
+
+- resign 'num'
+    This command specifies the threshold to resign. 'num' is a value
+    of the threshold. The default is around 1000.
+
+- stress on
+- stress off
+    When the command "stress on" is used, last-move shown in shogi
+    board is stressed. The default is on.
+
+- time remain 'num1' 'num2'
+    This command tells Bonanza the remaining time. 'num1' ('num2') is
+    the remaining time of black (white) in seconds.
+
+- time response 'num'
+    This command specifies a margin to control time. The time margin
+    saves Bonanza from time up due to TCP/IP communication to a server
+    program, sudden disc access, or imperfection of time control of
+    Bonanza. 'num' is the time margin in milli-second. The default
+    value is 200.
+
+- tlp 'num'
+    This command controls the number of threads to be created when
+    Bonana considers a move to make. The command becomes effective
+    when TLP macro is defined in the Makefile. 'num' is the number of
+    threads. The default value is 1.
+
+- #
+    A line beginning with # causes all characters on that line
+    to be ignored.
+
+- [move command]
+    A move command consists of four digits followed by two
+    capital alphabets, e.g. 7776FU. The first two digits
+    are a starting square and the last two are a target square. The
+    starting square is "OO" if the  move is a dorp, e.g. 0087FU. The
+    following two alphabets specify a piece type as the following,
+
+      FU - pawn             (Fuhyo)       TO - promoted pawn    (Tokin)
+      KY - lance            (Kyousha)     NY - promoted lance   (Narikyo)
+      KE - knight           (Keima)       NK - promoted knight  (Narikei)
+      GI - silver general   (Ginsho)      NG - promoted silver  (Narigin)
+      KI - gold general     (Kinsyo)
+      KA - Bishop           (Kakugyo)     UM - Dragon horse     (Ryuma)
+      HI - Rook             (Hisha)       RY - Dragon king      (Ryuo)
+      OU - King             (Osho)
+
+    Here, words in parentheses are romanization of Japanese words.
diff --git a/root.c b/root.c
new file mode 100644 (file)
index 0000000..e778431
--- /dev/null
+++ b/root.c
@@ -0,0 +1,249 @@
+#include <stdlib.h>
+#include <limits.h>
+#include "shogi.h"
+
+static int read_rest_list( tree_t * restrict ptree,
+                          unsigned int * restrict pmove_list );
+
+static int is_move_rest( unsigned int move,
+                        const unsigned int * restrict pmove_restraint );
+
+int
+make_root_move_list( tree_t * restrict ptree, int flag )
+{
+  unsigned int * restrict pmove;
+  unsigned int arestraint_list[ MAX_LEGAL_MOVES ];
+  int asort[ MAX_LEGAL_MOVES ];
+  unsigned int move, move_best;
+  int i, j, k, h, value, num_root_move, iret, value_pre_pv;
+  int value_best;
+
+  if ( flag & flag_refer_rest ) { read_rest_list( ptree, arestraint_list ); }
+  else                          { arestraint_list[0] = 0; }
+
+  pmove = ptree->move_last[0];
+  ptree->move_last[1] = GenCaptures( root_turn, pmove );
+  ptree->move_last[1] = GenNoCaptures( root_turn, ptree->move_last[1] );
+  ptree->move_last[1] = GenDrop( root_turn, ptree->move_last[1] );
+  num_root_move = (int)( ptree->move_last[1] - pmove );
+
+  value_pre_pv = INT_MIN;
+  move_best    = 0;
+  value_best   = 0;
+  for ( i = 0; i < num_root_move; i++ )
+    {
+      if ( ! ( game_status & flag_nopeek )
+          && ( game_status & ( flag_puzzling | flag_pondering ) )
+          && i != 0
+          && ( i % 8 ) == 0 )
+       {
+         iret = next_cmdline( 0 );
+         if ( iret == -1 )
+           {
+             game_status |= flag_search_error;
+             return 1;
+           }
+         else if ( iret == -2 )
+           {
+             out_warning( "%s", str_error );
+             ShutdownClient;
+           }
+         else if ( game_status & flag_quit ) { return 1; }
+         else if ( iret )
+           {
+             iret = procedure( ptree );
+             if ( iret == -1 )
+               {
+                 game_status |= flag_search_error;
+                 next_cmdline( 1 );
+                 return 1;
+               }
+             else if ( iret == -2 )
+               {
+                 out_warning( "%s", str_error );
+                 next_cmdline( 1 );
+                 ShutdownClient;
+               }
+             else if ( iret == 1 ) { next_cmdline( 1 ); }
+
+             if ( game_status & ( flag_quit | flag_quit_ponder
+                                  | flag_suspend ) )
+               {
+                 return 1;
+               }
+           }
+       }
+
+      value = INT_MIN;
+      move  = pmove[i];
+
+      MakeMove( root_turn, move, 1 );
+      if ( ! InCheck( root_turn )
+          && ! is_move_rest( move, arestraint_list ) )
+       {
+         iret = no_rep;
+         if ( InCheck(Flip(root_turn)) )
+           {
+             ptree->nsuc_check[2]
+               = (unsigned char)( ptree->nsuc_check[0] + 1U );
+             if ( ptree->nsuc_check[2] >= 2 * 2 )
+               {
+                 iret = detect_repetition( ptree, 2, Flip(root_turn), 2 );
+               }
+           }
+
+         if ( iret == perpetual_check ) { value = INT_MIN; }
+         else {
+           ptree->current_move[1] = move;
+           value = -search_quies( ptree, -score_bound, score_bound,
+                                  Flip(root_turn), 2, 1 );
+           if ( value > value_best )
+             {
+               value_best = value;
+               move_best  = move;
+             }
+           if ( I2IsPromote(move) ) { value++; }
+           if ( move == ptree->pv[0].a[1] )
+             {
+               value_pre_pv = value;
+               value        = INT_MAX;
+             }
+         }
+       }
+      UnMakeMove( root_turn, move, 1 );
+      asort[i] = value;
+    }
+  if ( UToCap(move_best) ) { root_move_cap = 1; }
+
+  /* shell sort */
+  for ( k = SHELL_H_LEN - 1; k >= 0; k-- )
+    {
+      h = ashell_h[k];
+      for ( i = num_root_move-h-1; i >= 0; i-- )
+       {
+         value = asort[i];
+         move  = pmove[i];
+         for ( j = i+h; j < num_root_move && asort[j] > value; j += h )
+           {
+             asort[j-h] = asort[j];
+             pmove[j-h] = pmove[j];
+           }
+         asort[j-h] = value;
+         pmove[j-h] = move;
+       }
+    }
+
+  /* discard all of moves cause mate or perpetual check */
+  if ( asort[0] >= -score_max_eval )
+    {
+      for ( ; num_root_move; num_root_move-- )
+       {
+         if ( asort[num_root_move-1] >= -score_max_eval ) { break; }
+       }
+    }
+
+  /* discard perpetual checks */
+  else for ( ; num_root_move; num_root_move-- )
+    {
+      if ( asort[num_root_move-1] != INT_MIN ) { break; }
+    }
+
+  for ( i = 0; i < num_root_move; i++ )
+    {
+      root_move_list[i].move   = pmove[i];
+      root_move_list[i].nodes  = 0;
+      root_move_list[i].status = 0;
+    }
+  if ( value_pre_pv != INT_MIN ) { asort[0] = value_pre_pv; }
+  root_nmove = num_root_move;
+
+  if ( num_root_move > 1 && ! ( game_status & flag_puzzling ) )
+    {
+      int id_easy_move = 0;
+
+      if ( asort[0] > asort[1] + ( MT_CAP_DRAGON * 3 ) / 8 )
+       {
+         id_easy_move = 3;
+         easy_min     = - ( MT_CAP_DRAGON *  4 ) / 16;
+         easy_max     =   ( MT_CAP_DRAGON * 32 ) / 16;
+         easy_abs     =   ( MT_CAP_DRAGON * 19 ) / 16;
+       }
+      else if ( asort[0] > asort[1] + ( MT_CAP_DRAGON * 2 ) / 8 )
+       {
+         id_easy_move = 2;
+         easy_min     = - ( MT_CAP_DRAGON *  3 ) / 16;
+         easy_max     =   ( MT_CAP_DRAGON *  6 ) / 16;
+         easy_abs     =   ( MT_CAP_DRAGON *  9 ) / 16;
+       }
+      else if ( asort[0] > asort[1] + MT_CAP_DRAGON / 8
+               && asort[0] > - MT_CAP_DRAGON / 8
+               && I2From(pmove[0]) < nsquare )
+       {
+         id_easy_move = 1;
+         easy_min     = - ( MT_CAP_DRAGON *  2 ) / 16;
+         easy_max     =   ( MT_CAP_DRAGON *  4 ) / 16;
+         easy_abs     =   ( MT_CAP_DRAGON *  6 ) / 16;
+       }
+
+      if ( easy_abs )
+       {
+         Out( "\n    the root move %s looks easy (type %d).\n",
+              str_CSA_move(pmove[0]), id_easy_move );
+         Out( "    evasion:%d, capture:%d, promotion:%d, drop:%d, "
+              "value:%5d - %5d\n",
+              ptree->nsuc_check[1]        ? 1 : 0,
+              UToCap(pmove[0])            ? 1 : 0,
+              I2IsPromote(pmove[0])       ? 1 : 0,
+              I2From(pmove[0]) >= nsquare ? 1 : 0,
+              asort[0], asort[1] );
+         easy_value = asort[0];
+       }
+    }
+
+  return asort[0];
+}
+
+
+static int
+read_rest_list( tree_t * restrict ptree, unsigned int * restrict pmove_list )
+{
+  FILE *pf;
+  int iret, imove;
+  char a[65536];
+
+  pf = file_open( "restraint.dat", "r" );
+  if ( pf == NULL ) { return -2; }
+
+  for ( imove = 0; imove < MAX_LEGAL_MOVES; imove++ )
+    {
+#if defined(_MSC_VER)
+      iret = fscanf_s( pf, "%s\n", a, 65536 );
+#else
+      iret = fscanf( pf, "%s\n", a );
+#endif
+      if ( iret != 1 ) { break; }
+      iret = interpret_CSA_move( ptree, pmove_list+imove, a );
+      if ( iret < 0 )
+       {
+         file_close( pf );
+         return iret;
+       }
+    }
+
+  pmove_list[imove] = 0;
+
+  return file_close( pf );
+}
+
+
+static int
+is_move_rest( unsigned int move,
+             const unsigned int * restrict pmove_restraint )
+{
+  while ( *pmove_restraint )
+    {
+      if ( move == *pmove_restraint++ ) { return 1; }
+    }
+
+  return 0;
+}
diff --git a/sckt.c b/sckt.c
new file mode 100644 (file)
index 0000000..9bf0f3f
--- /dev/null
+++ b/sckt.c
@@ -0,0 +1,364 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#if ! defined(_WIN32)
+#  include <arpa/inet.h>
+#  include <sys/types.h>
+#  include <sys/socket.h>
+#  include <netdb.h>
+#  include <unistd.h>
+#endif
+#include "shogi.h"
+
+#if defined(CSA_LAN) || defined(DEKUNOBOU) || defined(MNJ_LAN)
+const char *
+str_WSAError( const char *str )
+{
+#  if defined(_WIN32)
+  snprintf( str_message, SIZE_MESSAGE, "%s:%d", str,  WSAGetLastError() );
+  str_message[SIZE_MESSAGE-1] = '\0';
+  return str_message;
+#  else
+  return str;
+#  endif
+}
+#endif
+
+
+#if defined(CSA_LAN)
+int
+client_next_game( tree_t * restrict ptree, const char *str_addr, int iport )
+{
+  int iret;
+  int my_turn;
+  const char *str_name1, *str_name2;
+  char buf1[SIZE_PLAYERNAME], buf2[SIZE_PLAYERNAME];
+
+  for ( ;; ) {
+
+    str_buffer_cmdline[0] = '\0';
+    sckt_csa = sckt_connect( str_addr, iport );
+    if ( sckt_csa == SCKT_NULL ) { return -2; }
+
+    str_name1 = str_name2 = NULL;
+    iret = sckt_out( sckt_csa, "LOGIN %s %s\n",
+                    client_str_id, client_str_pwd );
+    if ( iret < 0 ) { return iret; }
+
+    Out( "wait for next game-conditions...\n" );
+
+    my_turn = black;
+    for ( ;; ) {
+
+      iret = next_cmdline( 1 );
+      if ( iret < 0 ) { return iret; }
+      else if ( game_status & flag_quit ) { return 1; }
+      
+      if      ( ! strcmp( str_cmdline, "END Game_Summary" ) ) { break; }
+      else if ( ! strcmp( str_cmdline, "Your_Turn:-" ) ) { my_turn = white; }
+      else if ( ! memcmp( str_cmdline, "Name+:", 6 ) )
+       {
+         strncpy( buf1, str_cmdline+6, SIZE_PLAYERNAME-1 );
+         buf1[SIZE_PLAYERNAME-1] = '\0';
+         str_name1 = buf1;
+       }
+      else if ( ! memcmp( str_cmdline, "Name-:", 6 ) )
+       {
+         strncpy( buf2, str_cmdline+6, SIZE_PLAYERNAME-1 );
+         buf2[SIZE_PLAYERNAME-1] = '\0';
+         str_name2 = buf2;
+       }
+    }
+
+    iret = sckt_out( sckt_csa, "AGREE\n" );
+    if ( iret < 0 ) { return -2; }
+
+    iret = next_cmdline( 1 );
+    if ( iret < 0 ) { return iret; }
+    else if ( game_status & flag_quit ) { return 1; }
+
+    if ( ! memcmp( str_cmdline, "REJECT:", 7 ) )
+      {
+       ShutdownClient;
+       continue;
+      }
+    else if ( ! memcmp( str_cmdline, "START:", 6 ) )   { break; }
+
+    str_error = str_server_err;
+    return -2;
+  }
+
+  if ( ini_game( ptree, &min_posi_no_handicap, flag_history,
+                str_name1, str_name2 ) < 0 )
+    {
+      return -1;
+    }
+
+  if ( get_elapsed( &time_turn_start ) < 0 ) { return -1; }
+
+  client_turn   = my_turn;
+  client_ngame += 1;
+
+  Out( "Game Conditions (%dth):\n", client_ngame );
+  Out( "  my turn:%c\n", ach_turn[my_turn] );
+
+  if ( my_turn == root_turn )
+    {
+      iret = com_turn_start( ptree, 0 );
+      if ( iret < 0 ) { return iret; }
+    }
+
+  return 1;
+}
+#endif
+
+
+#if defined(CSA_LAN) || defined(MNJ_LAN)
+sckt_t
+sckt_connect( const char *str_addr, int iport )
+{
+  struct hostent *phe;
+  struct sockaddr_in sin;
+  sckt_t sd;
+  u_long ul_addr;
+
+#if defined(_WIN32)
+  {
+    WSADATA wsaData;
+    if ( WSAStartup( MAKEWORD(1,1), &wsaData ) )
+      {
+       str_error = str_WSAError( "WSAStartup() failed." );
+       return SCKT_NULL;
+      }
+  }
+#endif
+
+  ul_addr = inet_addr( str_addr );
+  if ( ul_addr == INADDR_NONE )
+    {
+      phe = gethostbyname( str_addr );
+      if ( ! phe )
+       {
+         str_error = str_WSAError( "gethostbyname() faild." );
+#if defined(_WIN32)
+         WSACleanup();
+#endif
+         return SCKT_NULL;
+       }
+      ul_addr = *( (u_long *)phe->h_addr_list[0] );
+    }
+
+  sd = socket( AF_INET, SOCK_STREAM, 0 );
+  if ( sd == SCKT_NULL )
+    {
+      str_error = str_WSAError( "socket() faild." );
+#if defined(_WIN32)
+      WSACleanup();
+#endif
+      return SCKT_NULL;
+    }
+
+  sin.sin_family      = AF_INET;
+  sin.sin_addr.s_addr = ul_addr;
+  sin.sin_port        = htons( (u_short)iport );
+  if ( connect( sd, (struct sockaddr *)&sin, sizeof(sin) ) == SOCKET_ERROR )
+    {
+      str_error = str_WSAError( "connect() faild." );
+#if defined(_WIN32)
+      WSACleanup();
+#endif
+      return SCKT_NULL;
+    }
+
+  return sd;
+}
+
+
+int
+sckt_shutdown( sckt_t sd )
+{
+  int iret;
+
+  if ( sd == SCKT_NULL ) { return 1; }
+  Out( "shut down connection\n" );
+
+#  if defined(_WIN32)
+  if ( shutdown( sd, SD_SEND ) == SOCKET_ERROR )
+    {
+      str_error = str_WSAError( "shutdown() faild." );
+      WSACleanup();
+      return -2;
+    }
+
+  for ( ;; ) {
+    iret = recv( sd, str_message, SIZE_MESSAGE, 0 );
+    if ( iret == SOCKET_ERROR )
+      {
+       str_error = str_WSAError( "recv() failed." );
+       WSACleanup();
+       return -2;
+      }
+    else if ( ! iret ) { break; }
+  }
+  
+  if ( closesocket( sd ) == SOCKET_ERROR )
+    {
+      str_error = str_WSAError( "closesocket() failed." );
+      WSACleanup();
+      return -2;
+    }
+
+  if ( WSACleanup() == SOCKET_ERROR )
+    {
+      str_error = str_WSAError( "WSACleanup() faild." );
+      return -2;
+    }
+
+  return 1;
+
+#  else
+  if ( shutdown( sd, SHUT_RD ) == -1 )
+    {
+      str_error = "shutdown() faild.";
+      return -2;
+    }
+
+  for ( ;; ) {
+    iret = (int)recv( sd, str_message, SIZE_MESSAGE, 0 );
+    if ( iret == -1 )
+      {
+       str_error = "recv() failed.";
+       return -2;
+      }
+    else if ( ! iret ) { break; }
+  }
+  
+  if ( close( sd ) == -1 )
+    {
+      str_error = "close() failed.";
+      return -2;
+    }
+
+  return 1;
+#  endif
+}
+
+
+int
+sckt_check( sckt_t sd )
+{
+  struct timeval tv;
+  fd_set readfds;
+  int iret;
+
+  tv.tv_sec = tv.tv_usec = 0;
+
+  FD_ZERO( &readfds );
+#  if defined(_MSC_VER)
+#    pragma warning(disable:4127)
+#  endif
+  FD_SET( sd, &readfds );
+#  if defined(_MSC_VER)
+#    pragma warning(default:4127)
+#  endif
+
+  iret = select( (int)sd+1, &readfds, NULL, NULL, &tv );
+  if ( iret == SOCKET_ERROR )
+    {
+      str_error = str_WSAError( "select() with a socket connected failed." );
+      return -2;
+    }
+
+  return iret;
+}
+
+
+int
+sckt_in( sckt_t sd, char *str, int n )
+{
+  struct timeval tv;
+  fd_set readfds;
+  int iret;
+
+  for ( ;; ) {
+    Out( "wait for a message ... " );
+
+    tv.tv_sec  = SEC_KEEP_ALIVE;
+    tv.tv_usec = 0;
+    FD_ZERO( &readfds );
+#  if defined(_MSC_VER)
+#    pragma warning(disable:4127)
+#  endif
+    FD_SET( sd, &readfds );
+#  if defined(_MSC_VER)
+#    pragma warning(default:4127)
+#  endif
+
+    iret = select( (int)sd+1, &readfds, NULL, NULL, &tv );
+    if ( iret == SOCKET_ERROR )
+      {
+       str_error = str_WSAError( "select() with a socket connected failed." );
+       return -1;
+      }
+    if ( iret )
+      {
+       Out( "done.\n" );
+       break;
+      }
+    Out( "time out.\n" );
+
+    if ( sckt_out( sd, "\n" ) == SOCKET_ERROR )
+      {
+       str_error = str_WSAError( "send() failed." );
+       return -1;
+      }
+  }
+
+  iret = recv( sd, str, n-1, 0 );
+  if ( iret == SOCKET_ERROR )
+    {
+      str_error = str_WSAError( "recv() failed." );
+      return -1;
+    }
+  *( str + iret ) = '\0';
+
+  if ( ! iret )
+    {
+      Out( "Connection closed.\n" );
+      return 0;
+    }
+
+  Out( "%s[END]\n", str );
+  
+  return iret;
+}
+
+
+int
+sckt_out( sckt_t sd, const char *fmt, ... )
+{
+  int nch;
+  char buf[256];
+  va_list arg;
+
+  va_start( arg, fmt );
+  nch = vsnprintf( buf, 256, fmt, arg );
+  va_end( arg );
+  if ( nch >= 256 || nch < 0 )
+    {
+      str_error = "buffer overflow at sckt_out()";
+      return -1;
+    }
+
+  Out( "- now sending the message: %s", buf );
+
+  if ( send( sd, buf, nch, 0 ) == SOCKET_ERROR )
+    {
+      str_error = str_WSAError( "send() failed." );
+      return -1;
+    }
+
+  return get_elapsed( &time_last_send );
+}
+#endif /* CSA_LAN || MNJ_LAN */
+
diff --git a/search.c b/search.c
new file mode 100644 (file)
index 0000000..d7ca199
--- /dev/null
+++ b/search.c
@@ -0,0 +1,1411 @@
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "shogi.h"
+
+static void hist_add( tree_t * restrict ptree, int ply );
+static void hist_good( tree_t * restrict ptree, unsigned int move, int ply,
+                      int depth, int turn );
+static int detect_signals( tree_t * restrict ptree );
+static int detect_rep( tree_t * restrict ptree, int ply, int turn );
+static int rep_type( const tree_t * restrict ptree, int n, int i, int ply,
+                    int turn );
+
+/* #define DBG_SEARCH */
+#if defined(DBG_SEARCH)
+#  define DOut( ... )  if ( dbg_flag ) { out( __VA_ARGS__ ); }
+#else
+#  define DOut( ... )
+#endif
+
+int
+search( tree_t * restrict ptree, int alpha, int beta, int turn, int depth,
+       int ply, unsigned int state_node )
+{
+  int value, alpha_old;
+
+  if ( ! ptree->nsuc_check[ply]        && depth < PLY_INC )
+    {
+      return search_quies( ptree, alpha, beta, turn, ply, 1 );
+    }
+
+
+#if defined(DBG_SEARCH)
+  int dbg_flag = 0;
+  if ( iteration_depth == 3 && ply == 3
+       && ! strcmp( str_CSA_move(ptree->current_move[1]),  "7776FU" )
+       && ! strcmp( str_CSA_move(ptree->current_move[2]),  "3334FU" ) )
+    {
+      dbg_flag = 1;
+      Out( "search start (d%.1f %" PRIu64 ")\n",
+          (double)depth / (double)PLY_INC, ptree->node_searched );
+    }
+#endif
+
+  ptree->node_searched++;
+
+  if ( ply >= PLY_MAX-1 )
+    {
+      value = evaluate( ptree, ply, turn );
+      if ( alpha < value && value < beta ) { pv_close( ptree, ply, no_rep ); }
+      MOVE_CURR = MOVE_NA;
+      return value;
+    }
+
+
+#if ! defined(MINIMUM)
+  if ( ! ( game_status & flag_learning ) )
+#endif
+    {
+      /* check time and input */
+#if defined(TLP)
+      if ( ! ptree->tlp_id )
+#endif
+       if ( node_next_signal < ++node_last_check && detect_signals( ptree ) )
+         {
+           root_abort = 1;
+           return 0;
+         }
+
+      /* repetitions */
+      ptree->nrep_tried++;
+      switch ( detect_rep( ptree, ply, turn ) )
+       {
+       case black_superi_rep:
+         value = turn ? -score_inferior : score_inferior;
+         if ( alpha < value
+              && value < beta ) { pv_close( ptree, ply, black_superi_rep ); }
+         ptree->nsuperior_rep++;
+         MOVE_CURR = MOVE_NA;
+         return value;
+         
+       case white_superi_rep:
+         value = turn ? score_inferior : -score_inferior;
+         if ( alpha < value
+              && value < beta ) { pv_close( ptree, ply, white_superi_rep ); }
+         ptree->nsuperior_rep++;
+         MOVE_CURR = MOVE_NA;
+         return value;
+         
+       case four_fold_rep:
+         if ( alpha < score_draw
+              && score_draw < beta ) { pv_close( ptree, ply, four_fold_rep );}
+         ptree->nfour_fold_rep++;
+         MOVE_CURR = MOVE_NA;
+         return score_draw;
+         
+       case perpetual_check:
+         ptree->nperpetual_check++;
+         MOVE_CURR = MOVE_NA;
+         return score_foul;
+         
+       case perpetual_check2:
+         if ( ply > 4 )
+           {
+             ptree->nperpetual_check++;
+             MOVE_CURR = MOVE_NA;
+             return -score_foul;
+           }
+         break;
+       }
+      
+      ptree->nreject_tried++;
+      if ( rejections_probe( ptree, turn, ply ) )
+       {
+         ptree->nreject_done++;
+         if ( alpha < score_inferior && score_inferior < beta )
+           {
+             pv_close( ptree, ply, turn ? white_superi_rep:black_superi_rep );
+           }
+         MOVE_CURR = MOVE_NA;
+         return score_inferior;
+       }
+    }
+
+  /*
+    no repetitions.  worst situation of this node is checkmate,
+    and the best is to force checkmate within 1-ply.
+  */
+  alpha_old = alpha;
+  value = - ( score_mate1ply + 2 - ply );
+  if ( alpha < value )
+    {
+      if ( beta <= value )
+       {
+         MOVE_CURR = MOVE_NA;
+         return value;
+       }
+      alpha = value;
+    }
+  else {
+    value = score_mate1ply + 1 - ply;
+    if ( value <= alpha ) { return value; }
+  }
+
+#if defined(NO_NULL_PRUNE)
+  state_node &= ~node_do_null;
+#endif
+
+  ptree->amove_hash[ply] = 0;
+#if ! defined(MINIMUM)
+  if ( ! ( game_status & flag_learning ) )
+#endif
+    {
+      /* probe the transposition table */
+      int tv = hash_probe( ptree, ply, depth, turn, alpha, beta, state_node );
+      switch ( tv )
+       {
+       case value_exact:
+         if ( alpha < HASH_VALUE )
+           {
+             if ( HASH_VALUE < beta ) { pv_close( ptree, ply, hash_hit ); }
+             else {
+               MOVE_CURR = ptree->amove_hash[ply];
+               assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+             }
+           }
+         return HASH_VALUE;
+         
+       case value_lower:
+         MOVE_CURR = ptree->amove_hash[ply];
+         assert( beta <= HASH_VALUE );
+         assert( ! IsMove(MOVE_CURR)
+                 || is_move_valid( ptree, MOVE_CURR, turn ) );
+         if ( beta == alpha_old + 1 ) { return HASH_VALUE; }
+         break;
+         
+       case value_upper:
+         assert( HASH_VALUE <= alpha );
+         if ( beta == alpha_old + 1 ) { return HASH_VALUE; }
+         break;
+         
+       default:
+         state_node = tv;
+       }
+    }
+
+  DOut( "\nhash cut passed" );
+
+  if ( depth >= REJEC_MIN_DEPTH ) { add_rejections( ptree, turn, ply ); }
+  
+
+  if ( ! ptree->nsuc_check[ply] )
+    {
+      /* detect a move mates in 3-ply */
+      if ( ( state_node & node_do_mate )
+          && is_mate_in3ply( ptree, turn, ply ) )
+       {
+         value = score_mate1ply + 1 - ply;
+         
+         hash_store( ptree, ply, depth, turn, value_exact, value,
+                     MOVE_CURR, 0 );
+         
+         if ( alpha < value
+              && value < beta ) { pv_close( ptree, ply, mate_search ); }
+      
+         if ( depth >= REJEC_MIN_DEPTH )
+           {
+             sub_rejections( ptree, turn, ply );
+           }
+         assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+         return value;
+       }
+
+
+      /* null move pruning */
+      if ( 2*PLY_INC <= depth
+          && ( state_node & node_do_null )
+          && beta == alpha_old + 1
+          && beta <= evaluate( ptree, ply, turn ) )
+       {
+         int null_depth, nrep;
+         
+         null_depth = NullDepth(depth);
+         nrep       = root_nrep + ply - 1;
+
+         MOVE_CURR                   = MOVE_PASS;
+         ptree->move_last[ply]       = ptree->move_last[ply-1];
+         ptree->stand_pat[ply+1]     = (short)( - ptree->stand_pat[ply] );
+         ptree->nsuc_check[ply+1]    = 0;
+         ptree->rep_board_list[nrep] = HASH_KEY;
+         ptree->rep_hand_list[nrep]  = HAND_B;
+         ptree->null_pruning_tried++;
+
+         value = -search( ptree, -beta, 1-beta, Flip(turn), null_depth, ply+1,
+                          node_do_mate | node_do_recap | node_do_futile );
+         if ( SEARCH_ABORT )
+           {
+             if ( depth >= REJEC_MIN_DEPTH )
+               {
+                 sub_rejections( ptree, turn, ply );
+               }
+             return 0;
+           }
+         
+         if ( beta <= value )
+           {
+             ptree->null_pruning_done++;
+             if ( null_depth < PLY_INC )
+               {
+                 hash_store( ptree, ply, depth, turn, value_lower,
+                             value, MOVE_NA, state_node );
+               }
+             if ( depth >= REJEC_MIN_DEPTH )
+               {
+                 sub_rejections( ptree, turn, ply );
+               }
+             
+             DOut( "\nnull move cut!\n" );
+
+             assert( ! IsMove(MOVE_CURR)
+                     || is_move_valid( ptree, MOVE_CURR, turn ) );
+             return value;
+           }
+         
+         DOut( "\nnull passed" );
+         
+         if ( value == - ( score_mate1ply - ply ) )
+           {
+             state_node |= node_mate_threat;
+           }
+       }
+    }
+
+  /* recursive iterative-deepening for pv nodes */
+  if ( ! ptree->amove_hash[ply]
+       && depth >= 3*PLY_INC
+       && ( ( alpha == root_alpha && beta == root_beta )
+           || ( alpha == -root_beta && beta == -root_alpha ) ) )
+    {
+      if ( depth >= REJEC_MIN_DEPTH ) { sub_rejections( ptree, turn, ply ); }
+      value = search( ptree, -score_bound, beta, turn, depth-2*PLY_INC, ply,
+                     node_do_mate | node_do_recap );
+      if ( SEARCH_ABORT ) { return 0; }
+
+      if ( beta <= value && IsMove(MOVE_CURR) )
+       {
+         ptree->amove_hash[ply] = MOVE_CURR;
+       }
+      else if ( value < beta && ply <= (int)ptree->pv[ply-1].length )
+       {
+         assert( -score_bound < value );
+         ptree->amove_hash[ply] = ptree->pv[ply-1].a[ply];
+       }
+      assert( ! ptree->amove_hash[ply]
+             || is_move_valid( ptree, ptree->amove_hash[ply], turn ) );
+
+      if ( depth >= REJEC_MIN_DEPTH ) { add_rejections( ptree, turn, ply ); }
+    }
+
+  {
+    int depth_reduced, first_move_expanded, new_depth, extension;
+    int state_node_new;
+
+    ptree->move_last[ply]             = ptree->move_last[ply-1];
+    ptree->anext_move[ply].next_phase = next_move_hash;
+    ptree->hist_nmove[ply]            = 0;
+    first_move_expanded               = 0;
+
+    evaluate( ptree, ply, turn );
+
+    /* expand all of off-springs */
+    while ( ptree->nsuc_check[ply]
+           ? gen_next_evasion( ptree, ply, turn )
+           : gen_next_move( ptree, ply, turn ) ) {
+
+      DOut( "\nexpand %s (%" PRIu64 ")",
+           str_CSA_move(MOVE_CURR), ptree->node_searched );
+
+      ptree->nsuc_check[ply+1] = 0U;
+      state_node_new           = ( node_do_mate | node_do_recap | node_do_null
+                                  | node_do_futile );
+      extension                = 0;
+      depth_reduced            = 0;
+
+      hist_add( ptree, ply );
+
+      /* decision of extensions */
+      if ( turn ? is_move_check_w( ptree, MOVE_CURR )
+                : is_move_check_b( ptree, MOVE_CURR ) )
+       {
+         ptree->check_extension_done++;
+         ptree->nsuc_check[ply+1]
+           = (unsigned char)( ptree->nsuc_check[ply-1] + 1U );
+         extension = EXT_CHECK;
+       }
+      else if ( ptree->nsuc_check[ply]
+               && ptree->move_last[ply] - ptree->move_last[ply-1] == 1 )
+       {
+         ptree->onerp_extension_done++;
+         extension = EXT_ONEREP;
+       }
+      else if ( ! ptree->nsuc_check[ply]
+               && ( state_node & node_do_recap )
+               && I2To(MOVE_CURR) == I2To(MOVE_LAST)
+               && ( MOVE_CURR == ptree->anext_move[ply].move_cap1
+                    || ( ( ptree->anext_move[ply].value_cap1
+                           < ( ptree->anext_move[ply].value_cap2
+                               + MT_CAP_PAWN ) )
+                         && MOVE_CURR == ptree->anext_move[ply].move_cap2 ))
+               && ( UToCap(MOVE_LAST)
+                    || ( I2IsPromote(MOVE_LAST)
+                         && I2PieceMove(MOVE_LAST) != silver ) ) )
+       {
+         ptree->recap_extension_done++;
+         state_node_new = node_do_null | node_do_mate | node_do_futile;
+         if ( ! I2IsPromote(MOVE_CURR)
+              && I2PieceMove(MOVE_LAST) == UToCap(MOVE_LAST) )
+           {
+             extension = EXT_RECAP2;
+           }
+         else { extension = EXT_RECAP1; }
+       }
+
+      LimitExtension( extension, ply );
+
+      new_depth = depth + extension - PLY_INC;
+
+      /* reductions */
+      if ( PLY_INC <= new_depth
+          && ! ( state_node & node_mate_threat )
+          && ! ptree->nsuc_check[ply]
+          && ! UToCap(MOVE_CURR)
+          && ! ( I2IsPromote(MOVE_CURR) && I2PieceMove(MOVE_CURR) != silver )
+          && ptree->amove_hash[ply]  != MOVE_CURR
+          && ptree->killers[ply].no1 != MOVE_CURR
+          && ptree->killers[ply].no2 != MOVE_CURR )
+       {
+         unsigned int key     = phash( MOVE_CURR, turn );
+         unsigned int good    = ptree->hist_good[key]  + 1;
+         unsigned int triedx8 = ( ptree->hist_tried[key] + 2 ) * 8U;
+
+         if ( beta != alpha_old + 1 ) {
+           
+           if      ( good * 62U < triedx8 ) { depth_reduced = PLY_INC * 4/2; }
+           else if ( good * 46U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
+           else if ( good * 34U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
+           else if ( good * 19U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }
+           
+         } else {
+           
+           if      ( good * 62U < triedx8 ) { depth_reduced = PLY_INC * 4/2; }
+           else if ( good * 46U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
+           else if ( good * 30U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
+           else if ( good * 12U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }
+         }
+
+         new_depth -= depth_reduced;
+       }
+      
+      /* futility pruning */
+      if ( ! ptree->nsuc_check[ply+1]
+          && ! ptree->nsuc_check[ply]
+          && new_depth < 3*PLY_INC )
+       {
+         int diff  = estimate_score_diff( ptree, MOVE_CURR, turn );
+         int bound = alpha;
+         
+         if      ( 2*PLY_INC <= new_depth ) { bound -= EFUTIL_MG2; }
+         else if ( 1*PLY_INC <= new_depth ) { bound -= EFUTIL_MG1; }
+         
+         if ( eval_max_score( ptree, MOVE_CURR, ptree->stand_pat[ply],
+                              turn, diff ) <= bound )
+           {
+             first_move_expanded += 1;
+             continue;
+           }
+       }
+
+      DOut( ", futil passed" );
+
+      MakeMove( turn, MOVE_CURR, ply );
+      if ( I2From(MOVE_CURR) < nsquare
+          && ! ptree->nsuc_check[ply]
+          && InCheck(turn) )
+       {
+         UnMakeMove( turn, MOVE_CURR, ply );
+         continue;
+       }
+
+      if ( ! ptree->nsuc_check[ply+1] && ! ptree->nsuc_check[ply] )
+       {
+         evaluate( ptree, ply+1, Flip(turn) );
+         assert( ptree->stand_pat[ply] != score_bound );
+
+         /* futility pruning */
+         if ( ( new_depth < PLY_INC && - ptree->stand_pat[ply+1] <= alpha )
+              || ( new_depth < 2*PLY_INC
+                   && - ptree->stand_pat[ply+1] <= alpha - EFUTIL_MG1 )
+              || ( new_depth < 3*PLY_INC
+                   && - ptree->stand_pat[ply+1] <= alpha - EFUTIL_MG2 ) )
+           {
+             first_move_expanded += 1;
+             UnMakeMove( turn, MOVE_CURR, ply );
+             continue;
+           }
+       }
+
+      if ( depth_reduced )
+       {
+         value = -search( ptree, -alpha-1, -alpha, Flip(turn), new_depth,
+                          ply + 1, state_node_new );
+         if ( ! SEARCH_ABORT && alpha < value )
+           {
+             new_depth += depth_reduced;
+             value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+                              ply+1, state_node_new );
+           }
+       }
+      else if ( ! first_move_expanded )
+       {
+         value = -search( ptree, -beta, -alpha, Flip(turn), new_depth, ply+1,
+                          state_node_new );
+       }
+      else {
+       value = -search( ptree, -alpha-1, -alpha, Flip(turn), new_depth,
+                        ply + 1, state_node_new );
+       if ( ! SEARCH_ABORT && alpha < value && beta != alpha+1 )
+         {
+           value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+                            ply + 1, state_node_new );
+         }
+      }
+
+      if ( SEARCH_ABORT )
+       {
+         UnMakeMove( turn, MOVE_CURR, ply );
+         if ( depth >= REJEC_MIN_DEPTH )
+           {
+             sub_rejections( ptree, turn, ply );
+           }
+         return 0;
+       }
+
+      UnMakeMove( turn, MOVE_CURR, ply );
+
+      if ( alpha < value )
+       {
+         if ( new_depth < PLY_INC
+              && ! ptree->nsuc_check[ply+1]
+              && ptree->stand_pat[ply] != score_bound )
+           {
+             check_futile_score_quies( ptree, MOVE_CURR,
+                                       ptree->stand_pat[ply],
+                                       -ptree->stand_pat[ply+1], turn );
+           }
+
+         if ( beta <= value )
+           {
+             DOut( ", beta cut (%" PRIu64 ")\n", ptree->node_searched );
+
+             hash_store( ptree, ply, depth, turn, value_lower, value,
+                         MOVE_CURR, state_node );
+             hist_good( ptree, MOVE_CURR, ply, depth, turn );
+
+             ptree->fail_high++;
+             if ( ! first_move_expanded ) { ptree->fail_high_first++; }
+             
+             if ( depth >= REJEC_MIN_DEPTH )
+               {
+                 sub_rejections( ptree, turn, ply );
+               }
+
+             assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+             return value;
+           }
+       }
+      if ( alpha < value ) { alpha = value; }
+
+      first_move_expanded += 1;
+#if defined(TLP)
+      if ( ! ( ptree->nsuc_check[ply]
+              && ptree->move_last[ply] - ptree->move_last[ply-1] < 4 )
+          && tlp_idle
+          && ( ( iteration_depth < 11 && PLY_INC * 3 <= depth )
+               || PLY_INC * 4 <= depth ) )
+       {
+         ptree->tlp_beta       = (short)beta;
+         ptree->tlp_best       = (short)alpha;
+         ptree->tlp_depth      = (unsigned char)depth;
+         ptree->tlp_state_node = (unsigned char)state_node;
+         ptree->tlp_turn       = (char)turn;
+         ptree->tlp_ply        = (char)ply;
+         if ( tlp_split( ptree ) )
+           {
+             if ( SEARCH_ABORT ) { return 0; }
+             value = ptree->tlp_best;
+             if ( alpha < value )
+               {
+                 if ( beta <= value )
+                   {
+                     if ( depth >= REJEC_MIN_DEPTH )
+                       {
+                         sub_rejections( ptree, turn, ply );
+                       }
+
+                     hash_store( ptree, ply, depth, turn, value_lower,
+                                 value, MOVE_CURR, state_node );
+                     
+                     hist_good( ptree, MOVE_CURR, ply, depth, turn );
+
+                     ptree->fail_high++;
+
+                     assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+                     return value;
+                   }
+                 alpha = value;
+               }
+             break;
+           }
+       }
+#endif
+    }
+
+    DOut( "\nall searched (%" PRIu64 ")\n", ptree->node_searched );
+
+    if ( depth >= REJEC_MIN_DEPTH ) { sub_rejections( ptree, turn, ply ); }
+
+    if ( ! first_move_expanded )
+      {
+#if ! defined(MINIMUM)
+       if ( (int)I2From( ptree->current_move[ply-1] ) == Drop2From( pawn ) )
+         {
+           out_warning( "A checkmate by dropping pawn!!" );
+         }
+#endif
+       if ( alpha != alpha_old ) { pv_close( ptree, ply, 0 ); } 
+       return alpha;
+      }
+
+
+    if ( alpha <= - ( score_mate1ply + 2 - ply ) )
+      {
+#if ! defined(MINIMUM)
+       out_warning( "A node returns a value lower than mate." );
+#endif
+       if ( alpha_old < -score_inferior && -score_inferior < beta )
+         {
+           pv_close( ptree, ply, turn ? black_superi_rep : white_superi_rep );
+         }
+       MOVE_CURR = MOVE_NA;
+       return -score_inferior;
+      }
+
+    if ( alpha != alpha_old )
+      {
+       hist_good( ptree, ptree->pv[ply].a[ply], ply, depth, turn );
+
+       pv_copy( ptree, ply );
+
+#if ! defined(MINIMUM)
+       if ( ! ( game_status & flag_learning ) )
+#endif
+         {
+           hash_store( ptree, ply, depth, turn, value_exact, alpha,
+                       ptree->pv[ply].a[ply], state_node );
+         }
+      }
+    else {
+      hash_store( ptree, ply, depth, turn, value_upper, alpha, MOVE_NA,
+                 state_node );
+    }
+  }
+  
+  return alpha;
+}
+
+
+#if defined(TLP)
+int
+tlp_search( tree_t * restrict ptree, int alpha, int beta, int turn,
+           int depth, int ply, unsigned int state_node )
+{
+  int value, new_depth, extension, state_node_new, iret, depth_reduced;
+  int alpha_old;
+
+  assert( depth >= 3*PLY_INC );
+
+  alpha_old = alpha;
+
+  for ( ;; ) {
+    lock( & ptree->tlp_ptree_parent->tlp_lock );
+    if ( ptree->nsuc_check[ply] )
+      {
+       iret = gen_next_evasion( ptree->tlp_ptree_parent, ply, turn );
+      }
+    else { iret = gen_next_move( ptree->tlp_ptree_parent, ply, turn ); }
+    MOVE_CURR = ptree->tlp_ptree_parent->current_move[ply];
+    hist_add( ptree->tlp_ptree_parent, ply );
+    unlock( & ptree->tlp_ptree_parent->tlp_lock );
+    if ( ! iret ) { break; }
+
+    ptree->nsuc_check[ply+1] = 0U;
+    state_node_new           = ( node_do_mate | node_do_recap | node_do_null
+                                | node_do_futile );
+    extension                = 0;
+    depth_reduced            = 0;
+
+    if ( turn ? is_move_check_w( ptree, MOVE_CURR )
+              : is_move_check_b( ptree, MOVE_CURR ) )
+      {
+       ptree->check_extension_done++;
+       ptree->nsuc_check[ply+1]
+         = (unsigned char)( ptree->nsuc_check[ply-1] + 1U );
+       extension = EXT_CHECK;
+      }
+    else if ( ! ptree->nsuc_check[ply] 
+             && ( state_node & node_do_recap )
+             && I2To(MOVE_CURR) == I2To(MOVE_LAST)
+             && ( MOVE_CURR == ptree->anext_move[ply].move_cap1
+                  || ( ( ptree->anext_move[ply].value_cap1
+                         < ptree->anext_move[ply].value_cap2 + MT_CAP_PAWN )
+                       && MOVE_CURR == ptree->anext_move[ply].move_cap2 ) )
+             && ( UToCap(MOVE_LAST)
+                  || ( I2IsPromote(MOVE_LAST)
+                       && I2PieceMove(MOVE_LAST) != silver ) ) )
+      {
+       ptree->recap_extension_done++;
+       state_node_new = node_do_null | node_do_mate | node_do_futile;
+       if ( ! I2IsPromote(MOVE_CURR)
+            && I2PieceMove(MOVE_LAST) == UToCap(MOVE_LAST) )
+         {
+           extension = EXT_RECAP2;
+         }
+       else { extension = EXT_RECAP1; }
+      }
+
+    LimitExtension( extension, ply );
+
+    new_depth = depth + extension - PLY_INC;
+    
+    /* reductions */
+    if ( ! ( state_node & node_mate_threat )
+        && ! ptree->nsuc_check[ply]
+        && ! UToCap(MOVE_CURR)
+        && ! ( I2IsPromote(MOVE_CURR) && I2PieceMove(MOVE_CURR) != silver )
+        && ptree->killers[ply].no1 != MOVE_CURR
+        && ptree->killers[ply].no2 != MOVE_CURR )
+      {
+         unsigned int key     = phash( MOVE_CURR, turn );
+         unsigned int good    = ptree->hist_good[key]  + 1;
+         unsigned int triedx8 = ( ptree->hist_tried[key] + 2 ) * 8U;
+
+         if ( beta != alpha_old + 1 ) {
+           
+           if      ( good * 62U < triedx8 ) { depth_reduced = PLY_INC * 4/2; }
+           else if ( good * 46U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
+           else if ( good * 34U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
+           else if ( good * 19U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }
+           
+         } else {
+           
+           if      ( good * 62U < triedx8 ) { depth_reduced = PLY_INC * 4/2; }
+           else if ( good * 46U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
+           else if ( good * 30U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
+           else if ( good * 12U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }
+         }
+
+         new_depth -= depth_reduced;
+      }
+    
+    if ( ! ptree->nsuc_check[ply+1]
+        && ! ptree->nsuc_check[ply]
+        && new_depth < 3*PLY_INC )
+      {
+       int diff  = estimate_score_diff( ptree, MOVE_CURR, turn );
+       int bound = alpha;
+       
+       if      ( 2*PLY_INC <= new_depth ) { bound -= EFUTIL_MG2; }
+       else if ( 1*PLY_INC <= new_depth ) { bound -= EFUTIL_MG1; }
+       
+       if ( eval_max_score( ptree, MOVE_CURR, ptree->stand_pat[ply],
+                            turn, diff ) <= bound )
+         {
+           continue;
+         }
+      }
+
+    MakeMove( turn, MOVE_CURR, ply );
+    if ( I2From(MOVE_CURR) < nsquare
+        && ! ptree->nsuc_check[ply]
+        && InCheck(turn) )
+      {
+       UnMakeMove( turn, MOVE_CURR, ply );
+       continue;
+      }
+
+    if ( ! ptree->nsuc_check[ply+1] && ! ptree->nsuc_check[ply] )
+      {
+       evaluate( ptree, ply+1, Flip(turn) );
+       assert( ptree->stand_pat[ply] != score_bound );
+
+       /* futility pruning */
+       if ( ( new_depth < PLY_INC && - ptree->stand_pat[ply+1] <= alpha )
+            || ( new_depth < 2*PLY_INC
+                 && - ptree->stand_pat[ply+1] <= alpha - EFUTIL_MG1 )
+            || ( new_depth < 3*PLY_INC
+                 && - ptree->stand_pat[ply+1] <= alpha - EFUTIL_MG2 ) )
+         {
+           UnMakeMove( turn, MOVE_CURR, ply );
+           continue;
+         }
+      }
+
+    value = -search( ptree, -alpha-1, -alpha, Flip(turn), new_depth,
+                    ply + 1, state_node_new );
+    if ( ! SEARCH_ABORT && alpha < value )
+      {
+       if ( ! depth_reduced && beta != alpha+1 )
+         {
+           value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+                            ply + 1, state_node_new );
+         }
+       else if ( depth_reduced )
+         {
+           new_depth += depth_reduced;
+           value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+                            ply + 1, state_node_new );
+         }
+      }
+    
+    UnMakeMove( turn, MOVE_CURR, ply );
+      
+    if ( SEARCH_ABORT ) { return 0; }
+
+    if ( alpha < value ) {
+
+      alpha = value;
+      if ( beta <= value ) {
+       int num;
+
+       lock( &tlp_lock );
+       if ( ptree->tlp_abort )
+         {
+           unlock( &tlp_lock );
+           return 0;
+         }
+       tlp_nabort += 1;
+
+       for ( num = 0; num < tlp_max; num++ )
+         if ( ptree->tlp_ptree_parent->tlp_ptrees_sibling[num]
+              && num != ptree->tlp_id )
+           tlp_set_abort( ptree->tlp_ptree_parent->tlp_ptrees_sibling[num] );
+       
+       unlock( &tlp_lock );
+       
+       return value;
+      }
+    }
+  }
+
+  return alpha;
+}
+#endif /* TLP */
+
+
+static int
+detect_signals( tree_t * restrict ptree )
+{
+  unsigned int tnow, telapsed, tpondered, tsearched, tcount, tlimit, tmax;
+  unsigned int tmax_limit_count, tlimit_count, u;
+  int iret, easy_time, last_value, stable;
+
+  if ( ! ( game_status & flag_nopeek ) )
+    {
+      /* peek input-buffer to find a command */
+      iret = next_cmdline( 0 );
+      if ( iret == -1 )
+       {
+         game_status |= flag_search_error;
+         return 1;
+       }
+      else if ( iret == -2 )
+       {
+         out_warning( "%s", str_error );
+         ShutdownClient;
+       }
+      else if ( game_status & flag_quit ) { return 1; } /* EOF */
+      else if ( iret )
+       {
+         /* a command is found */
+         iret = procedure( ptree );
+         if ( iret == -1 )
+           {
+             game_status |= flag_search_error;
+             next_cmdline( 1 );
+             return 1;
+           }
+         else if ( iret == -2 )
+           {
+             out_warning( "%s", str_error );
+             next_cmdline( 1 );
+             ShutdownClient;
+           }
+         else if ( iret == 1 ) { next_cmdline( 1 ); }
+
+         if ( game_status & ( flag_quit | flag_quit_ponder
+                              | flag_move_now | flag_suspend ) )
+           {
+             return 1;
+           }
+       }
+    }
+
+  /* check conditions of search-abortion, and obtain tnow and elapsed */
+  if ( node_limit <= ptree->node_searched ) { return 1; }
+
+  if ( get_elapsed( &tnow ) < 0 )
+    {
+      game_status |= flag_search_error;
+      return 1;
+    }
+
+  /* keep my connection alive */
+#if defined(CSA_LAN)
+  if ( sckt_csa != SCKT_NULL
+       && SEC_KEEP_ALIVE * 1000U < tnow - time_last_send
+       && sckt_out( sckt_csa, "\n" ) < 0 )
+    {
+      game_status |= flag_search_error;
+      return 1;
+    }
+#endif
+
+#if defined(MNJ_LAN)
+  if ( sckt_mnj != SCKT_NULL && 500U < tnow - time_last_send )
+    {
+      uint64_t nodes;
+
+#  if defined(TLP)
+      lock( &tlp_lock );
+      nodes = tlp_count_node( tlp_atree_work );
+      unlock( &tlp_lock );
+#  else
+      nodes = ptree->node_searched;
+#  endif
+
+      if ( sckt_out( sckt_mnj, "pid=%d n=%" PRIu64 "\n", mnj_posi_id,
+                    nodes ) < 0 )
+       {
+         game_status |= flag_search_error;
+         return 1;
+       }
+    }
+#endif
+
+  /* shortening the time limit by depth */
+  if (  time_limit != UINT_MAX
+       && sec_limit_depth < PLY_MAX
+       && iteration_depth + 10 >= (int)sec_limit_depth )
+    {
+      if      ( iteration_depth + 0 >= (int)sec_limit_depth ) { u =    1U; }
+      else if ( iteration_depth + 1 >= (int)sec_limit_depth ) { u =    3U; }
+      else if ( iteration_depth + 2 >= (int)sec_limit_depth ) { u =    7U; }
+      else if ( iteration_depth + 3 >= (int)sec_limit_depth ) { u =   15U; }
+      else if ( iteration_depth + 4 >= (int)sec_limit_depth ) { u =   31U; }
+      else if ( iteration_depth + 5 >= (int)sec_limit_depth ) { u =   63U; }
+      else if ( iteration_depth + 6 >= (int)sec_limit_depth ) { u =  127U; }
+      else if ( iteration_depth + 7 >= (int)sec_limit_depth ) { u =  255U; }
+      else if ( iteration_depth + 8 >= (int)sec_limit_depth ) { u =  511U; }
+      else if ( iteration_depth + 9 >= (int)sec_limit_depth ) { u = 1023U; }
+      else                                                    { u = 2047U; }
+      
+      tlimit = u * 1000U + 1000U - time_response;
+      tmax   = u * 5000U + 1000U - time_response;
+      if ( tlimit > time_limit )     { tlimit = time_limit; }
+      if ( tmax   > time_max_limit ) { tmax   = time_max_limit; }
+    }
+  else {
+    tlimit = time_limit;
+    tmax   = time_max_limit;
+  }
+
+  telapsed   = tnow            - time_turn_start;
+  tpondered  = time_turn_start - time_start;
+  tsearched  = tnow            - time_start;
+  easy_time  = 0;
+  last_value = root_turn ? -last_root_value : last_root_value;
+  stable     = ( tlimit != UINT_MAX
+                && ( ( root_alpha == root_value && ! root_nfail_low )
+                     || last_pv.type == four_fold_rep
+                     || ( root_nfail_high
+                          && root_value + MT_CAP_DRAGON/8 >= last_value ) ) );
+
+  if ( tlimit != tmax )
+    {
+      tcount           = tsearched;
+      tmax_limit_count = tmax;
+      tlimit_count     = tlimit;
+    }
+  else {
+    tcount           = telapsed;
+    tmax_limit_count = tmax   + tpondered;
+    tlimit_count     = tlimit + tpondered;
+  }
+
+  if ( ! ( game_status & flag_pondering )
+       && root_nmove == 1
+       && telapsed > 2000U - time_response ) { return 1; }
+
+  if ( tcount > tmax ) { return 1; }
+
+  if ( stable && tcount > tlimit ) { return 1; }
+  
+  if ( stable
+       && ( tmax_limit_count * 3U < ( time_last_search - time_start ) * 5U ) )
+    {
+#if defined(DBG_EASY)
+      if ( ! easy_move )
+       {
+         Out( "  The search can be terminated "
+              "before it reaches time-limit.\n" );
+         easy_move = ptree->pv[0].a[1];
+       }
+#else
+      Out( "  The search is terminated before it reaches time-limit.\n" );
+      return 1;
+#endif
+    }
+
+  if ( stable
+       && easy_abs > abs( last_value )
+       && easy_min < last_value - easy_value
+       && easy_max > last_value - easy_value )
+    {
+      u = tlimit_count / 5U;
+      if ( u < tpondered ) { ; }
+      else if ( u - tpondered < 2000U - time_response )
+       {
+         u = tpondered + 2000U - time_response;
+       }
+      else {
+       u = ( ( u - tpondered ) / 1000U + 1U ) * 1000U
+         + tpondered - time_response;
+      }
+
+      if ( tsearched > u )
+       {
+         Out( "  The root move %s counted as easy!!\n",
+              str_CSA_move(root_move_list[0].move) );
+#if defined(DBG_EASY)
+         easy_move = ptree->pv[0].a[1];
+         easy_abs  = 0;
+#else
+         return 1;
+#endif
+       }
+      else if ( tsearched + 500U > u ) { easy_time = 1; }
+    }
+
+  /* renew node_per_second */
+  {
+    double dn, dd;
+
+    dn = (double)node_last_check * 1000.0;
+    dd = (double)( tnow - time_last_check ) + 0.1;
+    u  = (unsigned int)( dn / dd );
+    if      ( node_per_second > u * 2U ) { node_per_second /= 2U; }
+    else if ( node_per_second < u / 2U ) { node_per_second *= 2U; }
+    else                                 { node_per_second  = u; }
+  }
+
+  /* renew node_next_signal */
+  if ( ! ( game_status & flag_pondering ) && root_nmove == 1 )
+    {
+      u = 2000U - time_response;
+    }
+  else { u = tlimit; }
+
+  if ( ! ( game_status & ( flag_pondering | flag_puzzling ) )
+       && ! easy_time
+       && u > tcount + 500U )
+    {
+      node_next_signal = node_per_second / 4U;
+    }
+  else { node_next_signal = node_per_second / 32U; }
+
+  /* renew time_last_check and node_last_check */
+  time_last_check = tnow;
+  node_last_check = 0;
+
+       
+  return 0;
+}
+
+
+int
+is_move_check_b( const tree_t * restrict ptree, unsigned int move )
+{
+  const int from = (int)I2From(move);
+  const int to   = (int)I2To(move);
+  int is_check, ipiece_move, idirec;
+  bitboard_t bb;
+
+  is_check = 0;
+
+  if ( from >= nsquare ) { ipiece_move = From2Drop(from); }
+  else {
+    ipiece_move = (int)I2PieceMove(move);
+    if ( I2IsPromote(move) ) { ipiece_move += promote; }
+    
+    idirec = (int)adirec[SQ_WKING][from];
+    if ( idirec && idirec != (int)adirec[SQ_WKING][to]
+        && is_pinned_on_white_king( ptree, from, idirec ) )
+      {
+       is_check = 1;
+       goto end;
+      }
+  }
+  
+  switch ( ipiece_move )
+    {
+    case pawn:
+      if ( BOARD[to-nfile] == -king ) { is_check = 1; }
+      break;
+         
+    case lance:
+      AttackBLance( bb, to );
+      if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+      break;
+      
+    case knight:
+      if ( BBContract(abb_b_knight_attacks[to],BB_WKING) ) { is_check = 1; }
+      break;
+      
+    case silver:
+      if ( BBContract(abb_b_silver_attacks[to],BB_WKING) ) { is_check = 1; }
+      break;
+      
+    case gold:        case pro_pawn:
+    case pro_lance:    case pro_knight:
+    case pro_silver:
+      if ( BBContract(abb_b_gold_attacks[to],BB_WKING) ) { is_check = 1; }
+      break;
+      
+    case bishop:
+      AttackBishop( bb, to );
+      if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+      break;
+      
+    case rook:
+      AttackRook( bb, to );
+      if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+      break;
+      
+    case king:
+      break;
+
+    case horse:
+      AttackHorse( bb, to );
+      if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+      break;
+      
+    default:
+      assert( ipiece_move == dragon );
+      AttackDragon( bb, to );
+      if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+      break;
+    }
+
+ end:
+  return is_check;
+}
+
+
+int
+is_move_check_w( const tree_t * restrict ptree, unsigned int move )
+{
+  const int from = (int)I2From(move);
+  const int to   = (int)I2To(move);
+  int is_check, ipiece_move, idirec;
+  bitboard_t bb;
+
+  is_check = 0;
+
+  if ( from >= nsquare ) { ipiece_move = From2Drop(from); }
+  else {
+    ipiece_move = (int)I2PieceMove(move);
+    if ( I2IsPromote(move) ) { ipiece_move += promote; }
+    
+    idirec = (int)adirec[SQ_BKING][from];
+    if ( idirec && idirec != (int)adirec[SQ_BKING][to]
+        && is_pinned_on_black_king( ptree, from, idirec ) )
+      {
+       is_check = 1;
+       goto end;
+      }
+  }
+  
+  switch ( ipiece_move )
+    {
+    case pawn:
+      if ( BOARD[to+nfile] == king ) { is_check = 1; }
+      break;
+      
+    case lance:
+      AttackWLance( bb, to );
+      if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+      break;
+      
+    case knight:
+      if ( BBContract(abb_w_knight_attacks[to],BB_BKING) ) { is_check = 1; }
+      break;
+      
+    case silver:
+      if ( BBContract(abb_w_silver_attacks[to],BB_BKING) ) { is_check = 1; }
+      break;
+      
+    case gold:        case pro_pawn:
+    case pro_lance:   case pro_knight:
+    case pro_silver:
+      if ( BBContract(abb_w_gold_attacks[to],BB_BKING) ) { is_check = 1; }
+      break;
+      
+    case bishop:
+      AttackBishop( bb, to );
+      if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+      break;
+      
+    case rook:
+      AttackRook( bb, to );
+      if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+      break;
+
+    case king:
+      break;
+
+    case horse:
+      AttackHorse( bb, to );
+      if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+      break;
+      
+    default:
+      assert( ipiece_move == dragon );
+      AttackDragon( bb, to );
+      if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+      break;
+    }
+
+ end:
+  return is_check;
+}
+
+
+void
+pv_close( tree_t * restrict ptree, int ply, int type )
+{
+  ptree->pv[ply-1].a[ply-1] = (ptree)->current_move[ply-1];
+  ptree->pv[ply-1].length   = (unsigned char)(ply-1);
+  ptree->pv[ply-1].type     = (unsigned char)type;
+  ptree->pv[ply-1].depth    = (unsigned char)iteration_depth;
+}
+
+
+void
+pv_copy( tree_t * restrict ptree, int ply )
+{
+  memcpy( &(ptree->pv[ply-1].a[ply]), &(ptree->pv[ply].a[ply]),
+         ( ptree->pv[ply].length-ply+1 ) * sizeof(unsigned int) );
+  ptree->pv[ply-1].type     = ptree->pv[ply].type;
+  ptree->pv[ply-1].length   = ptree->pv[ply].length;
+  ptree->pv[ply-1].depth    = ptree->pv[ply].depth;
+  ptree->pv[ply-1].a[ply-1] = ptree->current_move[ply-1];
+}
+
+
+static int
+detect_rep( tree_t * restrict ptree, int ply, int turn )
+{
+  if ( ply < 4 ) { return detect_repetition( ptree, ply, turn, 2 ); }
+  else {
+    int n, i, imin, iret;
+
+    n    = root_nrep + ply - 1;
+    imin = n - REP_MAX_PLY;
+    if ( imin < 0 ) { imin = 0; }
+
+    for ( i = n-2; i >= imin; i-- )
+      if ( ptree->rep_board_list[i] == HASH_KEY )
+       {
+         iret = rep_type( ptree, n, i, ply, turn );
+         if ( iret ) { return iret; }
+       }
+  }
+
+  return no_rep;
+}
+
+
+static int
+rep_type( const tree_t * restrict ptree, int n, int i, int ply, int turn )
+{
+  const unsigned int hand1 = HAND_B;
+  const unsigned int hand2 = ptree->rep_hand_list[i];
+      
+  if ( (n-i) & 1 )
+    {
+      if ( turn )
+       {
+         if ( is_hand_eq_supe( hand2, hand1 ) )  { return white_superi_rep; }
+       }
+      else if ( is_hand_eq_supe( hand1, hand2 ) ) { return black_superi_rep; }
+    }
+  else if ( hand1 == hand2 )
+    {
+      const int ncheck   = (int)ptree->nsuc_check[ply];
+      const int nchecked = (int)ptree->nsuc_check[ply-1];
+
+      if      ( ncheck   * 2 - 2 >= n-i ) { return perpetual_check; }
+      else if ( nchecked * 2     >= n-i ) { return perpetual_check2; }
+      else                                { return four_fold_rep; }
+    }
+  else if ( is_hand_eq_supe( hand1, hand2 ) ) { return black_superi_rep; }
+  else if ( is_hand_eq_supe( hand2, hand1 ) ) { return white_superi_rep; }
+
+  return no_rep;
+}
+
+
+static void
+hist_add( tree_t * restrict ptree, int ply )
+{
+  if ( ptree->nsuc_check[ply] ) { return; }
+  if ( UToCap(MOVE_CURR) )      { return; }
+  if ( I2IsPromote(MOVE_CURR)
+       && I2PieceMove(MOVE_CURR) != silver ) { return; } 
+
+  assert( ptree->hist_nmove[ply] < MAX_LEGAL_MOVES );
+  ptree->hist_move[ply][ ptree->hist_nmove[ply]++ ] = MOVE_CURR;
+}
+
+
+static void
+hist_good( tree_t * restrict ptree, unsigned int move_good, int ply,
+          int depth, int turn )
+{
+  unsigned int key, move;
+  int i, n, value, value_no1, value_no2;
+
+  if ( ptree->nsuc_check[ply] ) { return; }
+
+  value     = p_value_ex[15+UToCap(move_good)];
+  value_no1 = p_value_ex[15+BOARD[I2To(ptree->amove_killer[ply].no1)]];
+  value_no2 = p_value_ex[15+BOARD[I2To(ptree->amove_killer[ply].no2)]];
+  if ( move_good == ptree->anext_move[ply].move_cap1 )
+    {
+      if ( ( ptree->anext_move[ply].phase_done & phase_killer1 )
+          && UToFromToPromo(move_good) != ptree->amove_killer[ply].no1 )
+       {
+         ptree->amove_killer[ply].no1_value
+           = ptree->anext_move[ply].value_cap1 - value - 1;
+       }
+      if ( ( ptree->anext_move[ply].phase_done & phase_killer2 )
+          && UToFromToPromo(move_good) != ptree->amove_killer[ply].no2 )
+       {
+         ptree->amove_killer[ply].no2_value
+           = ptree->anext_move[ply].value_cap1 - value - 2;
+       }
+    }
+  else if ( UToFromToPromo(move_good) == ptree->amove_killer[ply].no1 )
+    {
+      if ( ( ptree->anext_move[ply].phase_done & phase_cap1 )
+          && ( ptree->amove_killer[ply].no1_value + value
+               < ptree->anext_move[ply].value_cap1 + 1 ) )
+       {
+         ptree->amove_killer[ply].no1_value
+           = ptree->anext_move[ply].value_cap1 - value + 1;
+       }
+      if ( ( ptree->anext_move[ply].phase_done & phase_killer2 )
+          && ( ptree->amove_killer[ply].no1_value + value
+               < ptree->amove_killer[ply].no2_value + value_no2 + 1 ) )
+       {
+         ptree->amove_killer[ply].no1_value
+           = ptree->amove_killer[ply].no2_value + value_no2 - value + 1;
+       }
+    }
+  else if ( UToFromToPromo(move_good) == ptree->amove_killer[ply].no2 )
+    {
+      unsigned int uswap;
+      int iswap;
+      
+      if ( ( ptree->anext_move[ply].phase_done & phase_cap1 )
+          && ( ptree->amove_killer[ply].no2_value + value
+               < ptree->anext_move[ply].value_cap1 + 1 ) )
+       {
+         ptree->amove_killer[ply].no2_value
+           = ptree->anext_move[ply].value_cap1 - value + 1;
+       }
+      if ( ( ptree->anext_move[ply].phase_done & phase_killer1 )
+          && ( ptree->amove_killer[ply].no2_value + value
+               < ptree->amove_killer[ply].no1_value + value_no1 + 1 ) )
+       {
+         ptree->amove_killer[ply].no2_value
+           = ptree->amove_killer[ply].no1_value + value_no1 - value + 1;
+       }
+
+      uswap = ptree->amove_killer[ply].no1;
+      ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2;
+      ptree->amove_killer[ply].no2 = uswap;
+         
+      iswap = ptree->amove_killer[ply].no1_value;
+      ptree->amove_killer[ply].no1_value = ptree->amove_killer[ply].no2_value;
+      ptree->amove_killer[ply].no2_value = iswap;
+    }
+  else {
+    ptree->amove_killer[ply].no2 = ptree->amove_killer[ply].no1;
+    ptree->amove_killer[ply].no1 = UToFromToPromo(move_good);
+
+    if ( ptree->anext_move[ply].phase_done & phase_killer1 )
+      {
+       i  = swap( ptree, move_good, -MT_CAP_ROOK, MT_CAP_ROOK, turn );
+       i -= value + 1;
+
+       if ( ptree->amove_killer[ply].no1_value > i )
+         {
+           ptree->amove_killer[ply].no1_value = i;
+         }
+      }
+    ptree->amove_killer[ply].no2_value = ptree->amove_killer[ply].no1_value;
+    ptree->amove_killer[ply].no1_value
+      = ptree->anext_move[ply].value_cap1 - value + 1;
+  }
+
+
+  if ( UToCap(move_good) ) { return; }
+  if ( I2IsPromote(move_good)
+       && I2PieceMove(move_good) != silver ) { return; }
+
+  if ( ptree->killers[ply].no1 != move_good )
+    {
+      ptree->killers[ply].no2 = ptree->killers[ply].no1;
+      ptree->killers[ply].no1 = move_good;
+    }
+
+  if ( depth < 1 ) { depth = 1; }
+
+  n = ptree->hist_nmove[ply];
+  for ( i = 0; i < n; i++ )
+    {
+      move = ptree->hist_move[ply][i];
+      assert( is_move_valid( ptree, move, turn ) );
+
+      key = phash( move, turn );
+      if ( ptree->hist_tried[key] >= HIST_MAX )
+       {
+         ptree->hist_good[key]  /= 2U;
+         ptree->hist_tried[key] /= 2U;
+       }
+
+      assert( ptree->hist_tried[key] < HIST_MAX );
+      ptree->hist_tried[key]
+       = (unsigned short)( (int)ptree->hist_tried[key] + depth );
+    }
+
+  assert( is_move_valid( ptree, move_good, turn ) );
+  key = phash( move_good, turn );
+
+  assert( ptree->hist_good[key] < HIST_MAX );
+  ptree->hist_good[key]
+    = (unsigned short)( (int)ptree->hist_good[key] + depth );
+}
diff --git a/searchr.c b/searchr.c
new file mode 100644 (file)
index 0000000..a3aba06
--- /dev/null
+++ b/searchr.c
@@ -0,0 +1,740 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "shogi.h"
+
+static int find_root_move( unsigned int move );
+static int save_result( tree_t * restrict ptree, int value, int beta,
+                       int turn );
+
+#if defined(MPV)
+static int mpv_set_bound( int alpha );
+static int mpv_find_min( int *pnum );
+static int mpv_add_result( tree_t * restrict ptree, int value );
+static void mpv_sub_result( unsigned int move );
+static void mpv_out( tree_t * restrict ptree, int turn, unsigned int time );
+#endif
+
+#if defined(NO_STDOUT) && defined(NO_LOGGING)
+#  define NextRootMove(a,b) next_root_move(a)
+static int next_root_move( tree_t * restrict ptree );
+#else
+#  define NextRootMove(a,b) next_root_move(a,b)
+static int next_root_move( tree_t * restrict ptree, int turn );
+#endif
+
+int
+searchr( tree_t * restrict ptree, int alpha, int beta, int turn, int depth )
+{
+  uint64_t root_nodes_start;
+  int value, first_move_expanded, i;
+  int new_depth, extension, ply, state_node_new;
+#if defined(MPV)
+  int bound = INT_MIN;
+#endif
+
+  first_move_expanded = 1;
+  ply                 = 1;
+  ptree->move_last[1] = ptree->move_last[0];
+
+  while( NextRootMove( ptree, turn ) )
+    {
+      root_nodes_start = ptree->node_searched;
+      MakeMove( turn, MOVE_CURR, 1 );
+
+      assert( ! InCheck( turn ) );
+
+      state_node_new = ( node_do_mate | node_do_null | node_do_futile
+                        | node_do_recap );
+      if ( InCheck(Flip(turn)) )
+       {
+         ptree->check_extension_done++;
+         ptree->nsuc_check[2] = (unsigned char)( ptree->nsuc_check[0] + 1U );
+         extension            = EXT_CHECK - PLY_INC;
+       }
+      else {
+       extension            = - PLY_INC;
+       ptree->nsuc_check[2] = 0;
+      }
+      
+      if ( first_move_expanded )
+       {
+#if defined(MPV)
+         if ( root_mpv ) { bound = alpha; }
+#endif
+         new_depth = depth + extension;
+         value = -search( ptree, -beta, -alpha, Flip(turn), new_depth, 2,
+                          state_node_new );
+         if ( root_abort )
+           {
+             UnMakeMove( turn, MOVE_CURR, 1 );
+             return 0;
+           }
+
+         if ( value <= alpha )
+           {
+             UnMakeMove( turn, MOVE_CURR, 1 );
+             return value;
+           }
+
+         first_move_expanded = 0;
+       }
+#if defined(MPV)
+      else if ( root_mpv )
+       {
+         bound = mpv_set_bound( alpha );
+         if ( depth + extension >= PLY_INC || ptree->nsuc_check[2] )
+           {
+             new_depth = depth + extension;
+             
+             value = -search( ptree, -bound-1, -bound, Flip(turn), new_depth,
+                              2, state_node_new );
+             if ( ! root_abort && bound < value )
+               {
+                 new_depth = depth + extension;
+                 value = -search( ptree, -beta, -bound, Flip(turn), new_depth,
+                                  2, state_node_new );
+               }
+             if ( root_abort )
+               {
+                 UnMakeMove( turn, MOVE_CURR, 1 );
+                 return 0;
+               }
+           }
+         else {
+           value = -search_quies( ptree, -beta, -bound, Flip(turn), 2, 1 );
+         }
+       }
+#endif /* MPV */
+      else {
+       new_depth = depth + extension;
+           
+       value = -search( ptree, -alpha-1, -alpha, Flip(turn), new_depth, 2,
+                        state_node_new );
+       if ( root_abort )
+         {
+           UnMakeMove( turn, MOVE_CURR, 1 );
+           return 0;
+         }
+       if ( alpha < value )
+         {
+           MnjOut( "pid=%d move=%s v=%dl n=% " PRIu64 " \n",
+                   mnj_posi_id, str_CSA_move(MOVE_CURR), alpha+1,
+                   ptree->node_searched );
+
+           new_depth = depth + extension;
+           easy_abs  = 0;
+           value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+                            2, state_node_new );
+           if ( root_abort )
+             {
+               const char *str;
+               double dvalue;
+               char ch;
+               
+               UnMakeMove( turn, MOVE_CURR, 1 );
+               pv_close( ptree, 2, pv_fail_high );
+               time_last_result     = time_last_check;
+               time_last_eff_search = time_last_search;
+               root_value           = alpha+1;
+               ptree->pv[0]         = ptree->pv[1];
+               if ( turn )
+                 {
+                   dvalue = -(double)alpha;
+                   ch     = '-';
+                 }
+               else {
+                 dvalue = alpha;
+                 ch     = '+';
+               }
+               str = str_CSA_move_plus( ptree, MOVE_CURR, 1, turn );
+               Out( "           %7.2f  1.%c%s [%c0!]\n",
+                    dvalue / 100.0, ch, str, ch );
+               if ( game_status & flag_pondering )
+                 {
+                   OutCsaShogi( "info%+.2f %c%s %c%s [%c0!]\n",
+                                dvalue / 100.0, ach_turn[Flip(turn)],
+                                str_CSA_move(ponder_move),
+                                ch, str, ch );
+                 }
+               else {
+                 OutCsaShogi( "info%+.2f %c%s [%c0!]\n",
+                              dvalue / 100.0, ch, str, ch );
+               }
+               return 0;
+             }
+         }
+      }
+
+      UnMakeMove( turn, MOVE_CURR, 1 );
+
+      i = find_root_move( MOVE_CURR );
+      root_move_list[i].nodes = ptree->node_searched - root_nodes_start;
+
+#if defined(MPV)
+      if ( root_mpv && value < beta )
+       {
+         mpv_sub_result( MOVE_CURR );
+         if ( bound < value && mpv_add_result( ptree, value ) < 0 )
+           {
+             game_status |= flag_search_error;
+             return 1;
+           }
+       }
+#endif
+      
+      if ( alpha < value )
+       {
+         if ( save_result( ptree, value, beta, turn ) < 0 )
+           {
+             game_status |= flag_search_error;
+             return 1;
+           }
+         if ( beta <= value )
+           {
+             hash_store( ptree, 1, depth, turn, value_lower, value,
+                         MOVE_CURR, 0 );
+             return value;
+           }
+         alpha = value;
+       }
+    }
+  if ( root_abort ) { return 0; }
+
+#if ! defined(MINIMUM)
+  if ( ! ( game_status & flag_learning ) )
+#endif
+    {
+      hash_store( ptree, 1, depth, turn, value_exact, alpha,
+                 ptree->pv[1].a[1], 0 );
+    }
+
+  return alpha;
+}
+
+
+void
+out_pv( tree_t * restrict ptree, int value, int turn, unsigned int time )
+{
+  const char *str;
+  double dvalue;
+  int ply, tt, is_out;
+
+  tt     = turn;
+  is_out = ( iteration_depth > 3 || abs(value) > score_max_eval ) ? 1 : 0;
+
+#if defined(MPV)
+  if ( root_mpv ) { is_out = 0; }
+#endif
+
+  if ( is_out )
+    {
+      str    = str_time_symple( time );
+      dvalue = (double)( turn ? -value : value ) / 100.0;
+      OutCsaShogi( "info%+.2f", dvalue );
+      if ( game_status & flag_pondering )
+       {
+         OutCsaShogi( " %c%s", ach_turn[Flip(turn)],
+                      str_CSA_move(ponder_move) );
+       }
+
+      if ( ptree->pv[0].length )
+       {
+         int i = find_root_move( ptree->pv[0].a[1] );
+         if ( root_move_list[i].status & flag_first )
+           {
+             Out( " %2d %6s %7.2f ", iteration_depth, str, dvalue );
+           }
+         else { Out( "    %6s %7.2f ", str, dvalue ); }
+       }
+    }
+
+  for ( ply = 1; ply <= ptree->pv[0].length; ply++ )
+    {
+      if ( is_out )
+       {
+         if ( ply > 1 && ! ( (ply-1) % 4 ) )
+           {
+             Out( "\n                   " );
+           }
+         str = str_CSA_move_plus( ptree, ptree->pv[0].a[ply], ply, tt );
+         OutCsaShogi( " %c%s", ach_turn[tt], str );
+         Out( "%2d.%c%-11s", ply, ach_turn[tt], str );
+       }
+
+      MakeMove( tt, ptree->pv[0].a[ply], ply );
+      tt    = Flip(tt);
+      value = -value;
+    }
+
+  if ( ptree->pv[0].type == hash_hit )
+    {
+      int i, value_type;
+
+      for ( ; ply < PLY_MAX; ply++ )
+       {
+         ptree->amove_hash[ply] = 0;
+         value_type = hash_probe( ptree, ply, 0, tt, -score_bound,
+                                  score_bound, 0 );
+         if ( ! ( value_type == value_exact
+                  && value   == HASH_VALUE
+                  && is_move_valid( ptree, ptree->amove_hash[ply], tt ) ) )
+           {
+             break;
+           }
+         ptree->pv[0].a[ply] = ptree->amove_hash[ply];
+         for ( i = 1; i < ply; i++ )
+           if ( ptree->pv[0].a[i] == ptree->pv[0].a[ply] ) { goto rep_esc; }
+         
+         if ( is_out )
+           {
+             if ( ply > 1 && ! ( (ply-1) % 4 ) )
+               {
+                 Out( "\n                   " );
+               }
+             str = str_CSA_move_plus( ptree, ptree->pv[0].a[ply], ply,
+                                      tt );
+             OutCsaShogi( " %c%s", ach_turn[tt], str );
+             Out( "%2d:%c%-11s", ply, ach_turn[tt], str );
+           }
+
+         MakeMove( tt, ptree->pv[0].a[ply], ply );
+         if ( InCheck(tt) )
+           {
+             UnMakeMove( tt, ptree->amove_hash[ply], ply );
+             break;
+           }
+         ptree->pv[0].length++;
+         tt    = Flip(tt);
+         value = -value;
+       }
+    }
+ rep_esc:
+
+  if ( is_out && ptree->pv[0].type != no_rep )
+    {
+      if ( (((ply-1) % 4) == 0) && (ply != 1) )
+       {
+         Out( "\n                   " );
+       }
+      str = NULL;
+      switch ( ptree->pv[0].type )
+       {
+       case perpetual_check:  str = "PER. CHECK";     break;
+       case four_fold_rep:    str = "REPETITION";     break;
+       case black_superi_rep:
+       case white_superi_rep: str = "SUPERI. POSI.";  break;
+       case prev_solution:    str = "PREV. SEARCH";   break;
+       case hash_hit:         str = "HASH HIT";       break;
+       case book_hit:         str = "BOOK HIT";       break;
+       case pv_fail_high:     str = "FAIL HIGH";      break;
+       case mate_search:      str = "MATE SEARCH";    break;
+       }
+      if ( str != NULL ) { Out( " <%s>", str ); }
+    }
+  for ( ply--; ply >= 1; ply-- )
+    {
+      tt = Flip(tt);
+      UnMakeMove( tt, ptree->pv[0].a[ply], ply );
+    }
+
+  if ( is_out )
+    {
+      OutCsaShogi( "\n" );
+      Out( "\n" );
+    }
+} 
+
+
+static int
+save_result( tree_t * restrict ptree, int value, int beta, int turn )
+{
+  root_move_t root_move_temp;
+  int i;
+
+  if ( get_elapsed( &time_last_result ) < 0 ) { return -1; }
+
+  i = find_root_move( ptree->current_move[1] );
+  if ( i )
+    {
+      root_move_temp = root_move_list[i];
+      for ( ; i > 0; i-- ) { root_move_list[i] = root_move_list[i-1]; }
+      root_move_list[0] = root_move_temp;
+    }
+
+  if ( beta <= value ) { pv_close( ptree, 2, pv_fail_high ); }
+
+  if ( ptree->pv[0].a[1] != ptree->pv[1].a[1] )
+    {
+      time_last_eff_search = time_last_search;
+    }
+
+  ptree->pv[0] = ptree->pv[1];
+  root_value   = value;
+
+  if ( value < beta )
+    {
+      MnjOut( "pid=%d move=%s v=%de n=%" PRIu64 "\n", mnj_posi_id,
+             str_CSA_move(ptree->pv[1].a[1]), value, ptree->node_searched );
+      out_pv( ptree, value, turn, time_last_result - time_start );
+    }
+
+  return 1;
+}
+
+
+static int
+#if defined(NO_STDOUT) && defined(NO_LOGGING)
+next_root_move( tree_t * restrict ptree )
+#else
+next_root_move( tree_t * restrict ptree, int turn )
+#endif
+{
+  int i, n;
+
+  n = root_nmove;
+  for ( i = 0; i < n; i++ )
+    {
+      if ( root_move_list[i].status & flag_searched ) { continue; }
+      root_move_list[i].status |= flag_searched;
+      ptree->current_move[1]    = root_move_list[i].move;
+
+#if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
+      if ( iteration_depth > 5 )
+       {
+         const char *str_move;
+         char str[9];
+         /* check: does this code have small impact on performance? */
+         str_move = str_CSA_move_plus( ptree, ptree->current_move[1], 1,
+                                       turn);
+         snprintf( str, 9, "%d/%d", i+1, root_nmove );
+         if ( root_move_list[i].status & flag_first )
+           {
+             Out( "(%2d)       %7s* 1.%c%s     \r",
+                  iteration_depth, str, ach_turn[turn], str_move );
+           }
+         else {
+           Out( "           %7s* 1.%c%s     \r",
+                str, ach_turn[turn], str_move );
+         }
+       }
+#endif
+      
+      return 1;
+    }
+  
+  return 0;
+}
+
+
+static int
+find_root_move( unsigned int move )
+{
+  int i, n;
+
+  n = root_nmove;
+  for ( i = 0; i < n; i++ )
+    if ( root_move_list[i].move == move ) { break; }
+
+  return i;
+}
+
+
+#if defined(MPV)
+static void
+mpv_out( tree_t * restrict ptree, int turn, unsigned int time )
+{
+  int mpv_out, ipv, best;
+
+  best    = (int)mpv_pv[0].a[0] - 32768;
+  mpv_out = ( iteration_depth > 3 || abs(best) > score_max_eval ) ? 1 : 0;
+
+  for ( ipv = 0; mpv_pv[ipv].length; ipv++ )
+    {
+      const char *str;
+      double dvalue;
+      int tt, is_out, value, ply;
+
+      assert( ipv < mpv_num*2 );
+      tt     = turn;
+      value  = (int)mpv_pv[ipv].a[0] - 32768;
+      if ( mpv_out && value > best - mpv_width && ipv < mpv_num )
+       {
+         is_out = 1;
+       }
+      else { is_out = 0; }
+
+      if ( is_out )
+       {
+         dvalue = (double)( turn ? -value : value ) / 100.0;
+         if ( is_out && ! ipv ) { OutCsaShogi( "info" ); }
+         if ( is_out && ipv )   { OutCsaShogi( ":" ); }
+
+         OutCsaShogi( "%+.2f", dvalue );
+         if ( game_status & flag_pondering )
+           {
+             OutCsaShogi( " %c%s", ach_turn[Flip(turn)],
+                          str_CSA_move(ponder_move) );
+           }
+
+         str = str_time_symple( time );
+         ply = mpv_pv[ipv].depth;
+         if ( ! ipv ) { Out( "o%2d %6s %7.2f ", ply, str, dvalue ); }
+         else         { Out( " %2d        %7.2f ", ply, dvalue ); }
+       }
+
+      for ( ply = 1; ply <= mpv_pv[ipv].length; ply++ )
+       {
+         if ( is_out )
+           {
+             if ( ply > 1 && ! ( (ply-1) % 4 ) )
+               {
+                 Out( "\n                   " );
+               }
+             str = str_CSA_move_plus( ptree, mpv_pv[ipv].a[ply], ply, tt );
+             OutCsaShogi( " %c%s", ach_turn[tt], str );
+             Out( "%2d.%c%-11s", ply, ach_turn[tt], str );
+           }
+         
+         assert( is_move_valid( ptree, mpv_pv[ipv].a[ply], tt ) );
+         MakeMove( tt, mpv_pv[ipv].a[ply], ply );
+         tt    = Flip(tt);
+         value = -value;
+       }
+
+      if ( mpv_pv[ipv].type == hash_hit )
+       {
+         int i, value_type;
+
+         for ( ; ply < PLY_MAX; ply++ )
+           {
+             ptree->amove_hash[ply] = 0;
+             value_type = hash_probe( ptree, ply, 0, tt, -score_bound,
+                                      score_bound, 0 );
+             if ( ! ( value_type == value_exact
+                      && value   == HASH_VALUE
+                      && is_move_valid(ptree,ptree->amove_hash[ply],tt) ) )
+               {
+                 break;
+               }
+             mpv_pv[ipv].a[ply] = ptree->amove_hash[ply];
+             for ( i = 1; i < ply; i++ )
+               if ( mpv_pv[ipv].a[i]
+                    == mpv_pv[ipv].a[ply] ) { goto rep_esc; }
+             
+             if ( is_out )
+               {
+                 if ( ply > 1 && ! ( (ply-1) % 4 ) )
+                   {
+                     Out( "\n                   " );
+                   }
+                 str = str_CSA_move_plus( ptree, mpv_pv[ipv].a[ply], ply,
+                                          tt );
+                 OutCsaShogi( " %c%s", ach_turn[tt], str );
+                 Out( "%2d:%c%-11s", ply, ach_turn[tt], str );
+               }
+
+             MakeMove( tt, mpv_pv[ipv].a[ply], ply );
+             if ( InCheck(tt) )
+               {
+                 UnMakeMove( tt, ptree->amove_hash[ply], ply );
+                 break;
+               }
+             mpv_pv[ipv].length++;
+             tt    = Flip(tt);
+             value = -value;
+           }
+       }
+    rep_esc:
+
+      if ( is_out && mpv_pv[ipv].type != no_rep )
+       {
+         if ( (((ply-1) % 4) == 0) && (ply != 1) )
+           {
+             Out( "\n                   " );
+           }
+         str = NULL;
+         switch ( mpv_pv[ipv].type )
+           {
+           case perpetual_check:  str = "PER. CHECK";     break;
+           case four_fold_rep:    str = "REPETITION";     break;
+           case black_superi_rep:
+           case white_superi_rep: str = "SUPERI. POSI.";  break;
+           case prev_solution:    str = "PREV. SEARCH";   break;
+           case hash_hit:         str = "HASH HIT";       break;
+           case book_hit:         str = "BOOK HIT";       break;
+           case pv_fail_high:     str = "FAIL HIGH";      break;
+           case mate_search:      str = "MATE SEARCH";    break;
+           }
+         if ( str != NULL ) { Out( " <%s>", str ); }
+       }
+      for ( ply--; ply >= 1; ply-- )
+       {
+         tt = Flip(tt);
+         UnMakeMove( tt, mpv_pv[ipv].a[ply], ply );
+       }
+
+      if ( is_out ) { Out( "\n" ); }
+    }
+
+  if ( mpv_out ) { OutCsaShogi( "\n" ); }
+} 
+
+
+static void
+mpv_sub_result( unsigned int move )
+{
+  int i;
+
+  for ( i = 0; mpv_pv[i].length; i++ )
+    {
+      assert( i < mpv_num*2 );
+      assert( i < root_nmove*2 );
+      assert( mpv_pv[i].depth <= iteration_depth );
+      assert( -score_bound < (int)mpv_pv[i].a[0]-32768 );
+      assert( (int)mpv_pv[i].a[0]-32768 < score_bound );
+
+      if ( mpv_pv[i].a[1] == move ) { break; }
+    }
+
+  for ( ; mpv_pv[i].length; i++ )
+    {
+      assert( i < mpv_num*2 );
+      assert( i < root_nmove*2 );
+      assert( mpv_pv[i].depth <= iteration_depth );
+      assert( -score_bound < (int)mpv_pv[i].a[0]-32768 );
+      assert( (int)mpv_pv[i].a[0]-32768 < score_bound );
+
+      mpv_pv[i] = mpv_pv[i+1];
+    }
+}
+
+
+static int
+mpv_add_result( tree_t * restrict ptree, int value )
+{
+  pv_t pv_tmp, pv;
+  unsigned int time;
+  int i, vmin, num;
+
+  vmin = mpv_find_min( &num );
+  assert( num <= mpv_num );
+  assert( num < root_nmove );
+  assert( -score_bound < value );
+  assert( value < score_bound  );
+
+  /* remove the weakest pv if all of slots are full */
+  if ( num == mpv_num )
+    {
+      for ( i = 0; mpv_pv[i].length; i++ )
+       {
+         assert( i < mpv_num*2 );
+         assert( i < root_nmove*2 );
+         assert( mpv_pv[i].depth <= iteration_depth );
+         assert( -score_bound < (int)mpv_pv[i].a[0]-32768 );
+         assert( (int)mpv_pv[i].a[0]-32768 < score_bound );
+
+         if ( mpv_pv[i].depth == iteration_depth
+              && mpv_pv[i].a[0] == (unsigned int)(vmin+32768) ) { break; }
+       }
+      assert( i != mpv_num*2 );
+      assert( mpv_pv[i].length );
+      do {
+       assert( i < mpv_num*2 );
+       assert( i < root_nmove*2 );
+       mpv_pv[i] = mpv_pv[i+1];
+       i++;
+      } while ( mpv_pv[i].length );
+    }
+
+  /* add a pv */
+  for ( i = 0; mpv_pv[i].length; i++ )
+    {
+      assert( i < mpv_num*2 );
+      assert( i < root_nmove*2 );
+      assert( -score_bound < (int)mpv_pv[i].a[0]-32768 );
+      assert( (int)mpv_pv[i].a[0]-32768 < score_bound );
+
+      if ( mpv_pv[i].a[0] < (unsigned int)(value+32768) ) { break; }
+    }
+
+  pv      = ptree->pv[1];
+  pv.a[0] = (unsigned int)(value+32768);
+  do {
+    assert( i < mpv_num*2 );
+    assert( i < root_nmove*2 );
+    pv_tmp      = mpv_pv[i];
+    mpv_pv[i] = pv;
+    pv          = pv_tmp;
+    i          += 1;
+  } while ( pv.length );
+
+  if ( get_elapsed( &time ) < 0 ) { return -1; }
+
+  mpv_out( ptree, root_turn, time - time_start );
+
+  return 1;
+}
+
+
+static int
+mpv_set_bound( int alpha )
+{
+  int bound, num, value;
+
+  bound = alpha - mpv_width;
+  if ( bound < -score_bound ) { bound = -score_bound; }
+
+  value = mpv_find_min( &num );
+  assert( num <= mpv_num );
+  assert( num < root_nmove );
+  assert( num );
+  assert( -score_bound < value );
+  assert( value < score_bound  );
+  if ( num == mpv_num && bound < value ) { bound = value; }
+
+  return bound;
+}
+
+
+static int
+mpv_find_min( int *pnum )
+{
+  int i, num;
+  unsigned int a[ MPV_MAX_PV+1 ], u, utemp;
+
+  a[0] = 0;
+  num  = 0;
+  for ( i = 0; mpv_pv[i].length; i++ )
+    {
+      assert( i < mpv_num*2 );
+      assert( i < root_nmove*2 );
+      assert( mpv_pv[i].depth <= iteration_depth );
+
+      if ( mpv_pv[i].depth == iteration_depth )
+       {
+         u = mpv_pv[i].a[0];
+         assert( -score_bound < (int)u-32768 );
+         assert( (int)u-32768 < score_bound );
+
+         for ( num = 0; u <= a[num]; num++ );
+         do {
+           assert( num < mpv_num );
+           assert( num < root_nmove );
+           utemp  = a[num];
+           a[num] = u;
+           u      = utemp;
+           num   += 1;
+         } while ( u );
+         a[num] = 0;
+       }
+    }
+
+  if ( pnum ) { *pnum = num; }
+
+  if ( num ) { return (int)a[num-1] - 32768; }
+
+  return 0;
+}
+#endif
diff --git a/shogi.h b/shogi.h
new file mode 100644 (file)
index 0000000..809e687
--- /dev/null
+++ b/shogi.h
@@ -0,0 +1,1444 @@
+#ifndef SHOGI_H
+#define SHOGI_H
+
+#include <stdio.h>
+#include "param.h"
+
+#if defined(_WIN32)
+
+#  include <Winsock2.h>
+#  define CONV_CDECL         __cdecl
+#  define SCKT_NULL         INVALID_SOCKET
+typedef SOCKET sckt_t;
+
+#else
+
+#  include <pthread.h>
+#  include <sys/times.h>
+#  define CONV_CDECL
+#  define SCKT_NULL         -1
+#  define SOCKET_ERROR      -1
+typedef int sckt_t;
+
+#endif
+
+/* Microsoft C/C++ */
+#if defined(_MSC_VER)
+
+#  define _CRT_DISABLE_PERFCRIT_LOCKS
+#  define UINT64_MAX    ULLONG_MAX
+#  define PRIu64        "I64u"
+#  define PRIx64        "I64x"
+#  define UINT64_C(u)  ( u )
+
+#  define restrict      __restrict
+#  define strtok_r      strtok_s
+#  define read          _read
+#  define strncpy( dst, src, len ) strncpy_s( dst, len, src, _TRUNCATE )
+#  define snprintf( buf, size, fmt, ... )   \
+          _snprintf_s( buf, size, _TRUNCATE, fmt, __VA_ARGS__ )
+#  define vsnprintf( buf, size, fmt, list ) \
+          _vsnprintf_s( buf, size, _TRUNCATE, fmt, list )
+typedef unsigned __int64 uint64_t;
+typedef volatile long lock_t;
+
+/* GNU C and Intel C/C++ on x86 and x86-64 */
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+
+#  include <inttypes.h>
+#  define restrict __restrict
+typedef volatile int lock_t;
+
+/* other targets. */
+#else
+
+#  include <inttypes.h>
+typedef pthread_mutex_t lock_t;
+extern unsigned char aifirst_one[512];
+extern unsigned char ailast_one[512];
+
+#endif
+
+/*
+  #define BK_ULTRA_NARROW
+  #define BK_COM
+  #define BK_SMALL
+  #define NO_NULL_PRUNE
+  #define NO_STDOUT
+  #define DBG_EASY
+*/
+
+#if defined(CSASHOGI)
+#  define NO_STDOUT
+#  if ! defined(WIN32_PIPE)
+#    define WIN32_PIPE
+#  endif
+#endif
+
+#if defined(TLP)
+#  define SHARE volatile
+#  define SEARCH_ABORT ( root_abort || ptree->tlp_abort )
+#else
+#  define SHARE
+#  define SEARCH_ABORT root_abort
+#endif
+
+#define QUIES_PLY_LIMIT         7
+#define SHELL_H_LEN             7
+#define MAX_ANSWER              8
+#define PLY_INC                 8
+#define PLY_MAX                 48
+#define RAND_N                  624
+#define TC_NMOVE                37U
+#define SEC_MARGIN              15U
+#define SEC_KEEP_ALIVE          180U
+#define TIME_RESPONSE           200U
+#define RESIGN_THRESHOLD       ( ( MT_CAP_DRAGON * 5 ) /  8 )
+#define BNZ_VER                 "Feliz 0.0"
+
+#define REP_MAX_PLY             32
+#define REP_HIST_LEN            256
+
+#define EHASH_MASK              0x3fffffU  /* occupies 32MB */
+
+#define MNJ_MASK                0xfffU
+
+#define HIST_SIZE               0x4000U
+#define HIST_INVALID            0xffffU
+#define HIST_MAX                0x1000U
+
+#define REJEC_MASK              0x0ffffU
+#define REJEC_MIN_DEPTH        ( ( PLY_INC  * 5 ) )
+
+#define EXT_RECAP1             ( ( PLY_INC  * 1 ) /  4 )
+#define EXT_RECAP2             ( ( PLY_INC  * 2 ) /  4 )
+#define EXT_ONEREP             ( ( PLY_INC  * 2 ) /  4 )
+#define EXT_CHECK              ( ( PLY_INC  * 4 ) /  4 )
+
+#define EFUTIL_MG1             ( ( MT_CAP_DRAGON * 2 ) /  8 )
+#define EFUTIL_MG2             ( ( MT_CAP_DRAGON * 2 ) /  8 )
+
+#define FMG_MG                 ( ( MT_CAP_DRAGON * 2 ) / 16 )
+#define FMG_MG_KING            ( ( MT_CAP_DRAGON * 3 ) / 16 )
+#define FMG_MG_MT              ( ( MT_CAP_DRAGON * 8 ) / 16 )
+#define FMG_MISC               ( ( MT_CAP_DRAGON * 2 ) /  8 )
+#define FMG_CAP                ( ( MT_CAP_DRAGON * 2 ) /  8 )
+#define FMG_DROP               ( ( MT_CAP_DRAGON * 2 ) /  8 )
+#define FMG_MT                 ( ( MT_CAP_DRAGON * 2 ) /  8 )
+#define FMG_MISC_KING          ( ( MT_CAP_DRAGON * 2 ) /  8 )
+#define FMG_CAP_KING           ( ( MT_CAP_DRAGON * 2 ) /  8 )
+
+#define HASH_REG_HIST_LEN       256
+#define HASH_REG_MINDIFF       ( ( MT_CAP_DRAGON * 1 ) /  8 )
+#define HASH_REG_THRESHOLD     ( ( MT_CAP_DRAGON * 8 ) /  8 )
+
+#define FV_WINDOW               256
+#define FV_SCALE                32
+#define FV_PENALTY             ( 0.2 / (double)FV_SCALE )
+
+#define MPV_MAX_PV              16
+
+#define TLP_MAX_THREADS         12
+#define TLP_NUM_WORK           ( TLP_MAX_THREADS * 8 )
+
+#define TIME_CHECK_MIN_NODE     10000U
+#define TIME_CHECK_MAX_NODE     100000U
+
+#define SIZE_FILENAME           256
+#define SIZE_PLAYERNAME         256
+#define SIZE_MESSAGE            512
+#define SIZE_CMDLINE            512
+#define SIZE_CSALINE            512
+#define SIZE_CMDBUFFER          512
+
+#define IsMove(move)           ( (move) & 0xffffffU )
+#define MOVE_NA                 0x00000000U
+#define MOVE_PASS               0x01000000U
+#define MOVE_PONDER_FAILED      0xfe000000U
+#define MOVE_RESIGN             0xff000000U
+#define MOVE_CHK_SET            0x80000000U
+#define MOVE_CHK_CLEAR          0x40000000U
+
+#define MAX_LEGAL_MOVES         700
+#define MAX_LEGAL_EVASION       256
+#define MOVE_LIST_LEN           16384
+
+#define MAX_SIZE_SECTION        0xffff
+#define NUM_SECTION             0x4000
+
+#define MATERIAL            (ptree->posi.material)
+#define HAND_B              (ptree->posi.hand_black)
+#define HAND_W              (ptree->posi.hand_white)
+
+#define BB_BOCCUPY          (ptree->posi.b_occupied)
+#define BB_BTGOLD           (ptree->posi.b_tgold)
+#define BB_B_HDK            (ptree->posi.b_hdk)
+#define BB_B_BH             (ptree->posi.b_bh)
+#define BB_B_RD             (ptree->posi.b_rd)
+#define BB_BPAWN_ATK        (ptree->posi.b_pawn_attacks)
+#define BB_BPAWN            (ptree->posi.b_pawn)
+#define BB_BLANCE           (ptree->posi.b_lance)
+#define BB_BKNIGHT          (ptree->posi.b_knight)
+#define BB_BSILVER          (ptree->posi.b_silver)
+#define BB_BGOLD            (ptree->posi.b_gold)
+#define BB_BBISHOP          (ptree->posi.b_bishop)
+#define BB_BROOK            (ptree->posi.b_rook)
+#define BB_BKING            (abb_mask[SQ_BKING])
+#define BB_BPRO_PAWN        (ptree->posi.b_pro_pawn)
+#define BB_BPRO_LANCE       (ptree->posi.b_pro_lance)
+#define BB_BPRO_KNIGHT      (ptree->posi.b_pro_knight)
+#define BB_BPRO_SILVER      (ptree->posi.b_pro_silver)
+#define BB_BHORSE           (ptree->posi.b_horse)
+#define BB_BDRAGON          (ptree->posi.b_dragon)
+
+#define BB_WOCCUPY          (ptree->posi.w_occupied)
+#define BB_WTGOLD           (ptree->posi.w_tgold)
+#define BB_W_HDK            (ptree->posi.w_hdk)
+#define BB_W_BH             (ptree->posi.w_bh)
+#define BB_W_RD             (ptree->posi.w_rd)
+#define BB_WPAWN_ATK        (ptree->posi.w_pawn_attacks)
+#define BB_WPAWN            (ptree->posi.w_pawn)
+#define BB_WLANCE           (ptree->posi.w_lance)
+#define BB_WKNIGHT          (ptree->posi.w_knight)
+#define BB_WSILVER          (ptree->posi.w_silver)
+#define BB_WGOLD            (ptree->posi.w_gold)
+#define BB_WBISHOP          (ptree->posi.w_bishop)
+#define BB_WROOK            (ptree->posi.w_rook)
+#define BB_WKING            (abb_mask[SQ_WKING])
+#define BB_WPRO_PAWN        (ptree->posi.w_pro_pawn)
+#define BB_WPRO_LANCE       (ptree->posi.w_pro_lance)
+#define BB_WPRO_KNIGHT      (ptree->posi.w_pro_knight)
+#define BB_WPRO_SILVER      (ptree->posi.w_pro_silver)
+#define BB_WHORSE           (ptree->posi.w_horse)
+#define BB_WDRAGON          (ptree->posi.w_dragon)
+
+#define OCCUPIED_FILE       (ptree->posi.occupied_rl90)
+#define OCCUPIED_DIAG1      (ptree->posi.occupied_rr45)
+#define OCCUPIED_DIAG2      (ptree->posi.occupied_rl45)
+#define BOARD               (ptree->posi.asquare)
+
+#define SQ_BKING            (ptree->posi.isquare_b_king)
+#define SQ_WKING            (ptree->posi.isquare_w_king)
+
+#define HASH_KEY            (ptree->posi.hash_key)
+#define HASH_VALUE          (ptree->sort_value[0])
+#define MOVE_CURR           (ptree->current_move[ply])
+#define MOVE_LAST           (ptree->current_move[ply-1])
+
+#define NullDepth(d) ( (d) <  PLY_INC*26/4 ? (d)-PLY_INC*12/4 :              \
+                     ( (d) <= PLY_INC*30/4 ? PLY_INC*14/4                    \
+                                           : (d)-PLY_INC*16/4) )
+
+#define LimitExtension(e,ply) if ( (e) && (ply) > 2 * iteration_depth ) {     \
+                                if ( (ply) < 4 * iteration_depth ) {          \
+                                  e *= 4 * iteration_depth - (ply);           \
+                                  e /= 2 * iteration_depth;                   \
+                                } else { e = 0; } }
+
+#define Flip(turn)          ((turn)^1)
+#define Inv(sq)             (nsquare-1-sq)
+#define PcOnSq(k,i)         pc_on_sq[k][(i)*((i)+3)/2]
+#define PcPcOnSq(k,i,j)     pc_on_sq[k][(i)*((i)+1)/2+(j)]
+
+/*
+  xxxxxxxx xxxxxxxx xxx11111  pawn
+  xxxxxxxx xxxxxxxx 111xxxxx  lance
+  xxxxxxxx xxxxx111 xxxxxxxx  knight
+  xxxxxxxx xx111xxx xxxxxxxx  silver
+  xxxxxxx1 11xxxxxx xxxxxxxx  gold
+  xxxxx11x xxxxxxxx xxxxxxxx  bishop
+  xxx11xxx xxxxxxxx xxxxxxxx  rook
+ */
+#define I2HandPawn(hand)       (((hand) >>  0) & 0x1f)
+#define I2HandLance(hand)      (((hand) >>  5) & 0x07)
+#define I2HandKnight(hand)     (((hand) >>  8) & 0x07)
+#define I2HandSilver(hand)     (((hand) >> 11) & 0x07)
+#define I2HandGold(hand)       (((hand) >> 14) & 0x07)
+#define I2HandBishop(hand)     (((hand) >> 17) & 0x03)
+#define I2HandRook(hand)        ((hand) >> 19)
+#define IsHandPawn(hand)       ((hand) & 0x000001f)
+#define IsHandLance(hand)      ((hand) & 0x00000e0)
+#define IsHandKnight(hand)     ((hand) & 0x0000700)
+#define IsHandSilver(hand)     ((hand) & 0x0003800)
+#define IsHandGold(hand)       ((hand) & 0x001c000)
+#define IsHandBishop(hand)     ((hand) & 0x0060000)
+#define IsHandRook(hand)       ((hand) & 0x0180000)
+/*
+  xxxxxxxx xxxxxxxx x1111111  destination
+  xxxxxxxx xx111111 1xxxxxxx  starting square or drop piece+nsquare-1
+  xxxxxxxx x1xxxxxx xxxxxxxx  flag for promotion
+  xxxxx111 1xxxxxxx xxxxxxxx  piece to move
+  x1111xxx xxxxxxxx xxxxxxxx  captured piece
+ */
+#define To2Move(to)             ((unsigned int)(to)   <<  0)
+#define From2Move(from)         ((unsigned int)(from) <<  7)
+#define Drop2Move(piece)        ((nsquare-1+(piece))  <<  7)
+#define Drop2From(piece)         (nsquare-1+(piece))
+#define FLAG_PROMO               (1U                  << 14)
+#define Piece2Move(piece)       ((piece)              << 15)
+#define Cap2Move(piece)         ((piece)              << 19)
+#define I2To(move)              (((move) >>  0) & 0x007fU)
+#define I2From(move)            (((move) >>  7) & 0x007fU)
+#define I2FromTo(move)          (((move) >>  0) & 0x3fffU)
+#define I2IsPromote(move)       ((move) & FLAG_PROMO)
+#define I2PieceMove(move)       (((move) >> 15) & 0x000fU)
+#define UToFromToPromo(u)       ( (u) & 0x7ffffU )
+#define UToCap(u)               (((u)    >> 19) & 0x000fU)
+#define From2Drop(from)         ((from)-nsquare+1)
+
+
+#define BBIni(bb)                (bb).p[0] = (bb).p[1] = (bb).p[2] = 0
+#define BBToU(bb)                ((bb).p[0] | (bb).p[1] | (bb).p[2])
+#define BBToUShift(bb)           ((bb).p[0]<<2 | (bb).p[1]<<1 | (bb).p[2])
+#define PopuCount(bb)            popu_count012( bb.p[0], bb.p[1], bb.p[2] )
+#define FirstOne(bb)             first_one012( bb.p[0], bb.p[1], bb.p[2] )
+#define LastOne(bb)              last_one210( bb.p[2], bb.p[1], bb.p[0] )
+
+#define BBCmp(bb1,bb2)           ( (bb1).p[0] != (bb2).p[0]                   \
+                                  || (bb1).p[1] != (bb2).p[1]                \
+                                  || (bb1).p[2] != (bb2).p[2] )
+
+#define BBNot(bb,bb1)            (bb).p[0] = ~(bb1).p[0],                     \
+                                 (bb).p[1] = ~(bb1).p[1],                     \
+                                 (bb).p[2] = ~(bb1).p[2]
+
+#define BBOr(bb,bb1,bb2)         (bb).p[0] = (bb1).p[0] | (bb2).p[0],         \
+                                 (bb).p[1] = (bb1).p[1] | (bb2).p[1],         \
+                                 (bb).p[2] = (bb1).p[2] | (bb2).p[2]
+
+#define BBAnd(bb,bb1,bb2)        (bb).p[0] = (bb1).p[0] & (bb2).p[0],         \
+                                 (bb).p[1] = (bb1).p[1] & (bb2).p[1],         \
+                                 (bb).p[2] = (bb1).p[2] & (bb2).p[2]
+
+#define BBXor(bb,b1,b2)          (bb).p[0] = (b1).p[0] ^ (b2).p[0],           \
+                                 (bb).p[1] = (b1).p[1] ^ (b2).p[1],           \
+                                 (bb).p[2] = (b1).p[2] ^ (b2).p[2]
+
+#define BBAndOr(bb,bb1,bb2)      (bb).p[0] |= (bb1).p[0] & (bb2).p[0],        \
+                                 (bb).p[1] |= (bb1).p[1] & (bb2).p[1],        \
+                                 (bb).p[2] |= (bb1).p[2] & (bb2).p[2]
+
+#define BBNotAnd(bb,bb1)         bb.p[0] &= ~bb1.p[0];                        \
+                                 bb.p[1] &= ~bb1.p[1];                        \
+                                 bb.p[2] &= ~bb1.p[2]
+
+#define BBContractShift(bb1,bb2) ( ( (bb1).p[0] & (bb2).p[0] ) << 2           \
+                                     | ( (bb1).p[1] & (bb2).p[1] ) << 1       \
+                                     | ( (bb1).p[2] & (bb2).p[2] ) )
+
+#define BBContract(bb1,bb2)      ( ( (bb1).p[0] & (bb2).p[0] )                \
+                                     | ( (bb1).p[1] & (bb2).p[1] )            \
+                                     | ( (bb1).p[2] & (bb2).p[2] ) )
+
+#define Xor(i,bb)            (bb).p[0] ^= abb_mask[i].p[0],      \
+                             (bb).p[1] ^= abb_mask[i].p[1],      \
+                             (bb).p[2] ^= abb_mask[i].p[2]
+
+#define XorFile(i,bb)        (bb).p[0] ^= abb_mask_rl90[i].p[0], \
+                             (bb).p[1] ^= abb_mask_rl90[i].p[1], \
+                             (bb).p[2] ^= abb_mask_rl90[i].p[2]
+
+#define XorDiag1(i,bb)       (bb).p[0] ^= abb_mask_rr45[i].p[0], \
+                             (bb).p[1] ^= abb_mask_rr45[i].p[1], \
+                             (bb).p[2] ^= abb_mask_rr45[i].p[2]
+
+#define XorDiag2(i,bb)       (bb).p[0] ^= abb_mask_rl45[i].p[0], \
+                             (bb).p[1] ^= abb_mask_rl45[i].p[1], \
+                             (bb).p[2] ^= abb_mask_rl45[i].p[2]
+
+#define SetClear(bb)         (bb).p[0] ^= (bb_set_clear.p[0]), \
+                             (bb).p[1] ^= (bb_set_clear.p[1]), \
+                             (bb).p[2] ^= (bb_set_clear.p[2])
+
+#define SetClearFile(i1,i2,bb) \
+    (bb).p[0] ^= ((abb_mask_rl90[i1].p[0])|(abb_mask_rl90[i2].p[0])), \
+    (bb).p[1] ^= ((abb_mask_rl90[i1].p[1])|(abb_mask_rl90[i2].p[1])), \
+    (bb).p[2] ^= ((abb_mask_rl90[i1].p[2])|(abb_mask_rl90[i2].p[2]))
+
+#define SetClearDiag1(i1,i2,bb) \
+    (bb).p[0] ^= ((abb_mask_rr45[i1].p[0])|(abb_mask_rr45[i2].p[0])), \
+    (bb).p[1] ^= ((abb_mask_rr45[i1].p[1])|(abb_mask_rr45[i2].p[1])), \
+    (bb).p[2] ^= ((abb_mask_rr45[i1].p[2])|(abb_mask_rr45[i2].p[2]))
+
+#define SetClearDiag2(i1,i2,bb) \
+    (bb).p[0] ^= ((abb_mask_rl45[i1].p[0])|(abb_mask_rl45[i2].p[0])), \
+    (bb).p[1] ^= ((abb_mask_rl45[i1].p[1])|(abb_mask_rl45[i2].p[1])), \
+    (bb).p[2] ^= ((abb_mask_rl45[i1].p[2])|(abb_mask_rl45[i2].p[2]))
+
+#define AttackFile(i)  (abb_file_attacks[i]                               \
+                         [((ptree->posi.occupied_rl90.p[aslide[i].irl90]) \
+                            >> aslide[i].srl90) & 0x7f])
+
+#define AttackRank(i)  (ai_rook_attacks_r0[i]                             \
+                         [((ptree->posi.b_occupied.p[aslide[i].ir0]       \
+                            |ptree->posi.w_occupied.p[aslide[i].ir0])     \
+                             >> aslide[i].sr0) & 0x7f ])
+
+#define AttackDiag1(i)                                         \
+          (abb_bishop_attacks_rr45[i]                        \
+            [((ptree->posi.occupied_rr45.p[aslide[i].irr45]) \
+               >> aslide[i].srr45) & 0x7f])
+
+#define AttackDiag2(i)                                         \
+          (abb_bishop_attacks_rl45[i]                        \
+            [((ptree->posi.occupied_rl45.p[aslide[i].irl45]) \
+               >> aslide[i].srl45) & 0x7f])
+
+#define BishopAttack0(i) ( AttackDiag1(i).p[0] | AttackDiag2(i).p[0] )
+#define BishopAttack1(i) ( AttackDiag1(i).p[1] | AttackDiag2(i).p[1] )
+#define BishopAttack2(i) ( AttackDiag1(i).p[2] | AttackDiag2(i).p[2] )
+#define AttackBLance(bb,i) BBAnd( bb, abb_minus_rays[i], AttackFile(i) )
+#define AttackWLance(bb,i) BBAnd( bb, abb_plus_rays[i],  AttackFile(i) )
+#define AttackHorse(bb,i)  AttackBishop(bb,i); BBOr(bb,bb,abb_king_attacks[i])
+#define AttackDragon(bb,i) AttackRook(bb,i);   BBOr(bb,bb,abb_king_attacks[i])
+
+#define InCheck(turn)                                        \
+         ( (turn) ? is_white_attacked( ptree, SQ_WKING )     \
+                  : is_black_attacked( ptree, SQ_BKING ) )
+
+#define MakeMove(turn,move,ply)                                \
+                ( (turn) ? make_move_w( ptree, move, ply ) \
+                         : make_move_b( ptree, move, ply ) )
+
+#define UnMakeMove(turn,move,ply)                                \
+                ( (turn) ? unmake_move_w( ptree, move, ply ) \
+                         : unmake_move_b( ptree, move, ply ) )
+
+#define IsMoveCheck( ptree, turn, move )                        \
+                ( (turn) ? is_move_check_w( ptree, move )   \
+                         : is_move_check_b( ptree, move ) )
+
+#define GenCaptures(turn,pmove) ( (turn) ? w_gen_captures( ptree, pmove )   \
+                                         : b_gen_captures( ptree, pmove ) )
+
+#define GenNoCaptures(turn,pmove)                                             \
+                               ( (turn) ? w_gen_nocaptures( ptree, pmove )  \
+                                        : b_gen_nocaptures( ptree, pmove ) )
+
+#define GenDrop(turn,pmove)     ( (turn) ? w_gen_drop( ptree, pmove )       \
+                                         : b_gen_drop( ptree, pmove ) )
+
+#define GenCapNoProEx2(turn,pmove)                                 \
+                ( (turn) ? w_gen_cap_nopro_ex2( ptree, pmove )   \
+                         : b_gen_cap_nopro_ex2( ptree, pmove ) )
+
+#define GenNoCapNoProEx2(turn,pmove)                                \
+                ( (turn) ? w_gen_nocap_nopro_ex2( ptree, pmove )  \
+                         : b_gen_nocap_nopro_ex2( ptree, pmove ) )
+
+#define GenEvasion(turn,pmove)                                  \
+                ( (turn) ? w_gen_evasion( ptree, pmove )      \
+                         : b_gen_evasion( ptree, pmove ) )
+
+#define GenCheck(turn,pmove)                                  \
+                ( (turn) ? w_gen_checks( ptree, pmove )      \
+                         : b_gen_checks( ptree, pmove ) )
+
+#define IsMateIn1Ply(turn)                                    \
+                ( (turn) ? is_w_mate_in_1ply( ptree )         \
+                         : is_b_mate_in_1ply( ptree ) )
+
+#define IsDiscoverBK(from,to)                                  \
+          idirec = (int)adirec[SQ_BKING][from],               \
+          ( idirec && ( idirec!=(int)adirec[SQ_BKING][to] )   \
+            && is_pinned_on_black_king( ptree, from, idirec ) )
+
+#define IsDiscoverWK(from,to)                                  \
+          idirec = (int)adirec[SQ_WKING][from],               \
+          ( idirec && ( idirec!=(int)adirec[SQ_WKING][to] )   \
+            && is_pinned_on_white_king( ptree, from, idirec ) )
+#define IsMateWPawnDrop(ptree,to) ( BOARD[(to)+9] == king                 \
+                                     && is_mate_w_pawn_drop( ptree, to ) )
+
+#define IsMateBPawnDrop(ptree,to) ( BOARD[(to)-9] == -king                \
+                                     && is_mate_b_pawn_drop( ptree, to ) )
+
+enum { b0000, b0001, b0010, b0011, b0100, b0101, b0110, b0111,
+       b1000, b1001, b1010, b1011, b1100, b1101, b1110, b1111 };
+
+enum { A9 = 0, B9, C9, D9, E9, F9, G9, H9, I9,
+           A8, B8, C8, D8, E8, F8, G8, H8, I8,
+           A7, B7, C7, D7, E7, F7, G7, H7, I7,
+           A6, B6, C6, D6, E6, F6, G6, H6, I6,
+           A5, B5, C5, D5, E5, F5, G5, H5, I5,
+           A4, B4, C4, D4, E4, F4, G4, H4, I4,
+           A3, B3, C3, D3, E3, F3, G3, H3, I3,
+           A2, B2, C2, D2, E2, F2, G2, H2, I2,
+           A1, B1, C1, D1, E1, F1, G1, H1, I1 };
+
+enum { promote = 8, empty = 0,
+       pawn, lance, knight, silver, gold, bishop, rook, king, pro_pawn,
+       pro_lance, pro_knight, pro_silver, piece_null, horse, dragon };
+
+enum { npawn_max = 18,  nlance_max  = 4,  nknight_max = 4,  nsilver_max = 4,
+       ngold_max = 4,   nbishop_max = 2,  nrook_max   = 2,  nking_max   = 2 };
+
+enum { rank1 = 0, rank2, rank3, rank4, rank5, rank6, rank7, rank8, rank9 };
+enum { file1 = 0, file2, file3, file4, file5, file6, file7, file8, file9 };
+
+enum { nhand = 7, nfile = 9,  nrank = 9,  nsquare = 81 };
+
+enum { mask_file1 = (( 1U << 18 | 1U << 9 | 1U ) << 8) };
+
+enum { flag_diag1 = b0001, flag_plus = b0010 };
+
+enum { score_draw     =     1,
+       score_max_eval = 30000,
+       score_mate1ply = 32598,
+       score_inferior = 32599,
+       score_bound    = 32600,
+       score_foul     = 32600 };
+
+enum { phase_hash      = b0001,
+       phase_killer1   = b0001 << 1,
+       phase_killer2   = b0010 << 1,
+       phase_killer    = b0011 << 1,
+       phase_cap1      = b0001 << 3,
+       phase_cap_misc  = b0010 << 3,
+       phase_cap       = b0011 << 3,
+       phase_history1  = b0001 << 5,
+       phase_history2  = b0010 << 5,
+       phase_history   = b0011 << 5,
+       phase_misc      = b0100 << 5 };
+
+enum { next_move_hash = 0,  next_move_capture,   next_move_history2,
+       next_move_misc };
+
+/* next_evasion_hash should be the same as next_move_hash */
+enum { next_evasion_hash = 0, next_evasion_genall, next_evasion_misc };
+
+enum { next_quies_gencap, next_quies_captures, next_quies_misc };
+
+enum { no_rep = 0, four_fold_rep, perpetual_check, perpetual_check2,
+       black_superi_rep, white_superi_rep, hash_hit, prev_solution, book_hit,
+       pv_fail_high, mate_search };
+
+enum { record_misc, record_eof, record_next, record_resign, record_drawn,
+       record_error };
+
+enum { black = 0, white = 1 };
+
+enum { direc_misc           = b0000,
+       direc_file           = b0010, /* | */
+       direc_rank           = b0011, /* - */
+       direc_diag1          = b0100, /* / */
+       direc_diag2          = b0101, /* \ */
+       flag_cross           = b0010,
+       flag_diag            = b0100 };
+
+enum { value_null           = b0000,
+       value_upper          = b0001,
+       value_lower          = b0010,
+       value_exact          = b0011,
+       flag_value_up_exact  = b0001,
+       flag_value_low_exact = b0010,
+       node_do_null         = b0100,
+       node_do_recap        = b1000,
+       node_do_mate         = b0001 << 4,
+       node_mate_threat     = b0010 << 4, /* <- don't change it */ 
+       node_do_futile       = b0100 << 4,
+       state_node_end };
+/* note: maximum bits are 8.  tlp_state_node uses type unsigned char. */
+
+enum { flag_from_ponder     = b0001,
+       flag_refer_rest      = b0010 };
+
+enum { flag_time            = b0001,
+       flag_history         = b0010,
+       flag_rep             = b0100,
+       flag_detect_hang     = b1000,
+       flag_rejections      = b0001 << 4,
+       flag_nomake_move     = b0010 << 4,
+       flag_nofmargin       = b0100 << 4 };
+
+/* flags represent status of root move */
+enum { flag_searched        = b0001,
+       flag_failhigh        = b0010,
+       flag_faillow         = b0100,
+       flag_first           = b1000 };
+
+enum { flag_mated           = b0001,
+       flag_resigned        = b0010,
+       flag_drawn           = b0100,
+       flag_suspend         = b1000,
+       mask_game_end        = b1111,
+       flag_quit            = b0001 << 4,
+       flag_puzzling        = b0010 << 4,
+       flag_pondering       = b0100 << 4,
+       flag_thinking        = b1000 << 4,
+       flag_problem         = b0001 << 8,
+       flag_move_now        = b0010 << 8,
+       flag_quit_ponder     = b0100 << 8,
+       flag_search_error    = b0001 << 12,
+       flag_quiet           = b0010 << 12,
+       flag_reverse         = b0100 << 12,
+       flag_narrow_book     = b1000 << 12,
+       flag_time_extendable = b0001 << 16,
+       flag_learning        = b0010 << 16,
+       flag_nobeep          = b0100 << 16,
+       flag_nostress        = b1000 << 16,
+       flag_nopeek          = b0001 << 20,
+       flag_noponder        = b0010 << 20,
+       flag_noprompt        = b0100 << 20 };
+
+
+enum { flag_hand_pawn       = 1 <<  0,
+       flag_hand_lance      = 1 <<  5,
+       flag_hand_knight     = 1 <<  8,
+       flag_hand_silver     = 1 << 11,
+       flag_hand_gold       = 1 << 14,
+       flag_hand_bishop     = 1 << 17,
+       flag_hand_rook       = 1 << 19 };
+
+enum { f_hand_pawn   =    0,
+       e_hand_pawn   =   19,
+       f_hand_lance  =   38,
+       e_hand_lance  =   43,
+       f_hand_knight =   48,
+       e_hand_knight =   53,
+       f_hand_silver =   58,
+       e_hand_silver =   63,
+       f_hand_gold   =   68,
+       e_hand_gold   =   73,
+       f_hand_bishop =   78,
+       e_hand_bishop =   81,
+       f_hand_rook   =   84,
+       e_hand_rook   =   87,
+       fe_hand_end   =   90,
+       f_pawn        =   81,
+       e_pawn        =  162,
+       f_lance       =  225,
+       e_lance       =  306,
+       f_knight      =  360,
+       e_knight      =  441,
+       f_silver      =  504,
+       e_silver      =  585,
+       f_gold        =  666,
+       e_gold        =  747,
+       f_bishop      =  828,
+       e_bishop      =  909,
+       f_horse       =  990,
+       e_horse       = 1071,
+       f_rook        = 1152,
+       e_rook        = 1233,
+       f_dragon      = 1314,
+       e_dragon      = 1395,
+       fe_end        = 1476,
+
+       kkp_hand_pawn   =   0,
+       kkp_hand_lance  =  19,
+       kkp_hand_knight =  24,
+       kkp_hand_silver =  29,
+       kkp_hand_gold   =  34,
+       kkp_hand_bishop =  39,
+       kkp_hand_rook   =  42,
+       kkp_hand_end    =  45,
+       kkp_pawn        =  36,
+       kkp_lance       = 108,
+       kkp_knight      = 171,
+       kkp_silver      = 252,
+       kkp_gold        = 333,
+       kkp_bishop      = 414,
+       kkp_horse       = 495,
+       kkp_rook        = 576,
+       kkp_dragon      = 657,
+       kkp_end         = 738 };
+
+enum { pos_n = fe_end * ( fe_end + 1 ) / 2 };
+
+typedef struct { unsigned int p[3]; } bitboard_t;
+
+typedef struct { bitboard_t gold, silver, knight, lance; } check_table_t;
+
+#if ! defined(MINIMUM)
+typedef struct { fpos_t fpos;  unsigned int games, moves, lines; } rpos_t;
+typedef struct {
+  double pawn, lance, knight, silver, gold, bishop, rook;
+  double pro_pawn, pro_lance, pro_knight, pro_silver, horse, dragon;
+  float pc_on_sq[nsquare][fe_end*(fe_end+1)/2];
+  float kkp[nsquare][nsquare][kkp_end];
+} param_t;
+#endif
+
+typedef enum { mode_write, mode_read_write, mode_read } record_mode_t;
+
+typedef struct { uint64_t word1, word2; }                        trans_entry_t;
+typedef struct { trans_entry_t prefer, always[2]; }              trans_table_t;
+typedef struct { int count;  unsigned int cnst[2], vec[RAND_N]; }rand_work_t;
+
+typedef struct {
+  uint64_t root;
+  SHARE uint64_t sibling;
+} rejections_t;
+
+typedef struct {
+  int no1_value, no2_value;
+  unsigned int no1, no2;
+} move_killer_t;
+
+typedef struct { unsigned int no1, no2; } killer_t;
+
+typedef struct {
+  union { char str_move[ MAX_ANSWER ][ 8 ]; } info;
+  char str_name1[ SIZE_PLAYERNAME ];
+  char str_name2[ SIZE_PLAYERNAME ];
+  FILE *pf;
+  unsigned int games, moves, lines;
+} record_t;
+
+typedef struct {
+  unsigned int a[PLY_MAX];
+  unsigned char type;
+  unsigned char length;
+  unsigned char depth;
+} pv_t;
+
+typedef struct {
+  unsigned char ir0,   sr0;
+  unsigned char irl90, srl90;
+  unsigned char irl45, srl45;
+  unsigned char irr45, srr45;
+} slide_tbl_t;
+
+
+typedef struct {
+  uint64_t hash_key;
+  bitboard_t b_occupied,     w_occupied;
+  bitboard_t occupied_rl90,  occupied_rl45, occupied_rr45;
+  bitboard_t b_hdk,          w_hdk;
+  bitboard_t b_tgold,        w_tgold;
+  bitboard_t b_bh,           w_bh;
+  bitboard_t b_rd,           w_rd;
+  bitboard_t b_pawn_attacks, w_pawn_attacks;
+  bitboard_t b_lance,        w_lance;
+  bitboard_t b_knight,       w_knight;
+  bitboard_t b_silver,       w_silver;
+  bitboard_t b_bishop,       w_bishop;
+  bitboard_t b_rook,         w_rook;
+  bitboard_t b_horse,        w_horse;
+  bitboard_t b_dragon,       w_dragon;
+  bitboard_t b_pawn,         w_pawn;
+  bitboard_t b_gold,         w_gold;
+  bitboard_t b_pro_pawn,     w_pro_pawn;
+  bitboard_t b_pro_lance,    w_pro_lance;
+  bitboard_t b_pro_knight,   w_pro_knight;
+  bitboard_t b_pro_silver,   w_pro_silver;
+  unsigned int hand_black, hand_white;
+  int material;
+  signed char asquare[nsquare];
+  unsigned char isquare_b_king, isquare_w_king;
+} posi_t;
+
+
+typedef struct {
+  unsigned int hand_black, hand_white;
+  char turn_to_move;
+  signed char asquare[nsquare];
+} min_posi_t;
+
+typedef struct {
+  uint64_t nodes;
+  unsigned int move, status;
+} root_move_t;
+
+typedef struct {
+  unsigned int *move_last;
+  unsigned int move_cap1;
+  unsigned int move_cap2;
+  int phase_done, next_phase, remaining, value_cap1, value_cap2;
+} next_move_t;
+
+/* data: 31  1bit flag_learned */
+/*       30  1bit is_flip      */
+/*       15 16bit value        */
+typedef struct {
+  uint64_t key_book;
+  unsigned int key_responsible, key_probed, key_played;
+  unsigned int hand_responsible, hand_probed, hand_played;
+  unsigned int move_played, move_responsible, move_probed, data;
+} history_book_learn_t;
+
+typedef struct tree tree_t;
+struct tree {
+  posi_t posi;
+  uint64_t rep_board_list[ REP_HIST_LEN ];
+  uint64_t node_searched;
+  unsigned int *move_last[ PLY_MAX ];
+  next_move_t anext_move[ PLY_MAX ];
+  pv_t pv[ PLY_MAX ];
+  move_killer_t amove_killer[ PLY_MAX ];
+  unsigned int null_pruning_done;
+  unsigned int null_pruning_tried;
+  unsigned int check_extension_done;
+  unsigned int recap_extension_done;
+  unsigned int onerp_extension_done;
+  unsigned int neval_called;
+  unsigned int nquies_called;
+  unsigned int nfour_fold_rep;
+  unsigned int nperpetual_check;
+  unsigned int nsuperior_rep;
+  unsigned int nrep_tried;
+  unsigned int nreject_tried;
+  unsigned int nreject_done;
+  unsigned int ntrans_always_hit;
+  unsigned int ntrans_prefer_hit;
+  unsigned int ntrans_probe;
+  unsigned int ntrans_exact;
+  unsigned int ntrans_lower;
+  unsigned int ntrans_upper;
+  unsigned int ntrans_superior_hit;
+  unsigned int ntrans_inferior_hit;
+  unsigned int fail_high;
+  unsigned int fail_high_first;
+  unsigned int rep_hand_list[ REP_HIST_LEN ];
+  unsigned int amove_hash[ PLY_MAX ];
+  unsigned int amove[ MOVE_LIST_LEN ];
+  unsigned int current_move[ PLY_MAX ];
+  killer_t killers[ PLY_MAX ];
+  unsigned int hist_nmove[ PLY_MAX ];
+  unsigned int hist_move[ PLY_MAX ][ MAX_LEGAL_MOVES ];
+  int sort_value[ MAX_LEGAL_MOVES ];
+  unsigned short hist_tried[ HIST_SIZE ];
+  unsigned short hist_good[ HIST_SIZE ];
+  short save_material[ PLY_MAX ];
+  short stand_pat[ PLY_MAX+1 ];
+  unsigned char nsuc_check[ PLY_MAX+1 ];
+#if defined(TLP)
+  struct tree *tlp_ptrees_sibling[ TLP_MAX_THREADS ];
+  struct tree *tlp_ptree_parent;
+  lock_t tlp_lock;
+  volatile int tlp_abort;
+  volatile int tlp_used;
+  unsigned short tlp_slot;
+  short tlp_beta;
+  short tlp_best;
+  volatile unsigned char tlp_nsibling;
+  unsigned char tlp_depth;
+  unsigned char tlp_state_node;
+  unsigned char tlp_id;
+  char tlp_turn;
+  char tlp_ply;
+#endif
+};
+
+
+extern SHARE unsigned int game_status;
+extern history_book_learn_t history_book_learn[ HASH_REG_HIST_LEN ];
+
+extern int npawn_box;
+extern int nlance_box;
+extern int nknight_box;
+extern int nsilver_box;
+extern int ngold_box;
+extern int nbishop_box;
+extern int nrook_box;
+
+extern unsigned int ponder_move_list[ MAX_LEGAL_MOVES ];
+extern unsigned int ponder_move;
+extern int ponder_nmove;
+
+extern root_move_t root_move_list[ MAX_LEGAL_MOVES ];
+extern SHARE int root_abort;
+extern int root_nrep;
+extern int root_nmove;
+extern int root_value;
+extern int root_alpha;
+extern int root_beta;
+extern int root_turn;
+extern int root_move_cap;
+extern int root_nfail_high;
+extern int root_nfail_low;
+extern int resign_threshold;
+extern int n_nobook_move;
+
+extern uint64_t node_limit;
+extern unsigned int node_per_second;
+extern unsigned int node_next_signal;
+extern unsigned int node_last_check;
+
+extern unsigned int hash_mask;
+extern int trans_table_age;
+
+extern pv_t last_pv;
+extern pv_t last_pv_save;
+extern int last_root_value;
+extern int last_root_value_save;
+
+extern SHARE trans_table_t *ptrans_table;
+extern trans_table_t *ptrans_table_orig;
+extern int log2_ntrans_table;
+
+extern int depth_limit;
+
+extern unsigned int time_last_result;
+extern unsigned int time_last_eff_search;
+extern unsigned int time_last_search;
+extern unsigned int time_last_check;
+extern unsigned int time_turn_start;
+extern unsigned int time_start;
+extern unsigned int time_max_limit;
+extern unsigned int time_limit;
+extern unsigned int time_response;
+extern unsigned int sec_limit;
+extern unsigned int sec_limit_up;
+extern unsigned int sec_limit_depth;
+extern unsigned int sec_elapsed;
+extern unsigned int sec_b_total;
+extern unsigned int sec_w_total;
+
+extern record_t record_problems;
+extern record_t record_game;
+extern FILE *pf_book;
+extern FILE *pf_hash;
+extern int irecord_game;
+
+extern short p_value[31];
+extern short pc_on_sq[nsquare][fe_end*(fe_end+1)/2];
+extern short kkp[nsquare][nsquare][kkp_end];
+
+extern uint64_t ehash_tbl[ EHASH_MASK + 1 ];
+extern unsigned char hash_rejections_parent[ REJEC_MASK+1 ];
+extern rejections_t hash_rejections[ REJEC_MASK+1 ];
+extern rand_work_t rand_work;
+extern slide_tbl_t aslide[ nsquare ];
+extern bitboard_t abb_b_knight_attacks[ nsquare ];
+extern bitboard_t abb_b_silver_attacks[ nsquare ];
+extern bitboard_t abb_b_gold_attacks[ nsquare ];
+extern bitboard_t abb_w_knight_attacks[ nsquare ];
+extern bitboard_t abb_w_silver_attacks[ nsquare ];
+extern bitboard_t abb_w_gold_attacks[ nsquare ];
+extern bitboard_t abb_king_attacks[ nsquare ];
+extern bitboard_t abb_obstacle[ nsquare ][ nsquare ];
+extern bitboard_t abb_bishop_attacks_rl45[ nsquare ][ 128 ];
+extern bitboard_t abb_bishop_attacks_rr45[ nsquare ][ 128 ];
+extern bitboard_t abb_file_attacks[ nsquare ][ 128 ];
+extern bitboard_t abb_mask[ nsquare ];
+extern bitboard_t abb_mask_rl90[ nsquare ];
+extern bitboard_t abb_mask_rl45[ nsquare ];
+extern bitboard_t abb_mask_rr45[ nsquare ];
+extern bitboard_t abb_plus_rays[ nsquare ];
+extern bitboard_t abb_minus_rays[ nsquare ];
+extern uint64_t b_pawn_rand[ nsquare ];
+extern uint64_t b_lance_rand[ nsquare ];
+extern uint64_t b_knight_rand[ nsquare ];
+extern uint64_t b_silver_rand[ nsquare ];
+extern uint64_t b_gold_rand[ nsquare ];
+extern uint64_t b_bishop_rand[ nsquare ];
+extern uint64_t b_rook_rand[ nsquare ];
+extern uint64_t b_king_rand[ nsquare ];
+extern uint64_t b_pro_pawn_rand[ nsquare ];
+extern uint64_t b_pro_lance_rand[ nsquare ];
+extern uint64_t b_pro_knight_rand[ nsquare ];
+extern uint64_t b_pro_silver_rand[ nsquare ];
+extern uint64_t b_horse_rand[ nsquare ];
+extern uint64_t b_dragon_rand[ nsquare ];
+extern uint64_t b_hand_pawn_rand[ npawn_max ];
+extern uint64_t b_hand_lance_rand[ nlance_max ];
+extern uint64_t b_hand_knight_rand[ nknight_max ];
+extern uint64_t b_hand_silver_rand[ nsilver_max ];
+extern uint64_t b_hand_gold_rand[ ngold_max ];
+extern uint64_t b_hand_bishop_rand[ nbishop_max ];
+extern uint64_t b_hand_rook_rand[ nrook_max ];
+extern uint64_t w_pawn_rand[ nsquare ];
+extern uint64_t w_lance_rand[ nsquare ];
+extern uint64_t w_knight_rand[ nsquare ];
+extern uint64_t w_silver_rand[ nsquare ];
+extern uint64_t w_gold_rand[ nsquare ];
+extern uint64_t w_bishop_rand[ nsquare ];
+extern uint64_t w_rook_rand[ nsquare ];
+extern uint64_t w_king_rand[ nsquare ];
+extern uint64_t w_pro_pawn_rand[ nsquare ];
+extern uint64_t w_pro_lance_rand[ nsquare ];
+extern uint64_t w_pro_knight_rand[ nsquare ];
+extern uint64_t w_pro_silver_rand[ nsquare ];
+extern uint64_t w_horse_rand[ nsquare ];
+extern uint64_t w_dragon_rand[ nsquare ];
+extern uint64_t w_hand_pawn_rand[ npawn_max ];
+extern uint64_t w_hand_lance_rand[ nlance_max ];
+extern uint64_t w_hand_knight_rand[ nknight_max ];
+extern uint64_t w_hand_silver_rand[ nsilver_max ];
+extern uint64_t w_hand_gold_rand[ ngold_max ];
+extern uint64_t w_hand_bishop_rand[ nbishop_max ];
+extern uint64_t w_hand_rook_rand[ nrook_max ];
+extern unsigned int ai_rook_attacks_r0[ nsquare ][ 128 ];
+extern unsigned int move_evasion_pchk;
+extern int p_value_ex[31];
+extern int benefit2promo[15];
+extern int easy_abs;
+extern int easy_min;
+extern int easy_max;
+extern int easy_value;
+extern SHARE int fmg_misc;
+extern SHARE int fmg_cap;
+extern SHARE int fmg_drop;
+extern SHARE int fmg_mt;
+extern SHARE int fmg_misc_king;
+extern SHARE int fmg_cap_king;
+extern int iteration_depth;
+extern unsigned char book_section[ MAX_SIZE_SECTION+1 ];
+extern unsigned char adirec[nsquare][nsquare];
+extern unsigned char is_same[16][16];
+extern char str_message[ SIZE_MESSAGE ];
+extern char str_cmdline[ SIZE_CMDLINE ];
+extern char str_buffer_cmdline[ SIZE_CMDBUFFER ];
+extern const char *str_error;
+
+extern const char *astr_table_piece[ 16 ];
+extern const char *str_resign;
+extern const char *str_repetition;
+extern const char *str_jishogi;
+extern const char *str_record_error;
+extern const char *str_unexpect_eof;
+extern const char *str_ovrflw_line;
+extern const char *str_warning;
+extern const char *str_on;
+extern const char *str_off;
+extern const char *str_book;
+extern const char *str_hash;
+extern const char *str_fv;
+extern const char *str_book_error;
+extern const char *str_perpet_check;
+extern const char *str_bad_cmdline;
+extern const char *str_busy_think;
+extern const char *str_bad_record;
+extern const char *str_bad_board;
+extern const char *str_delimiters;
+extern const char *str_fmt_line;
+extern const char *str_illegal_move;
+extern const char *str_double_pawn;
+extern const char *str_mate_drppawn;
+extern const char *str_fopen_error;
+extern const char *str_game_ended;
+extern const char *str_io_error;
+extern const char *str_spaces;
+extern const char *str_king_hang;
+#if defined(CSA_LAN)
+extern const char *str_server_err;
+#endif
+extern const char *str_myname;
+extern const char *str_version;
+extern const min_posi_t min_posi_no_handicap;
+extern const short aipos[31];
+extern const char ach_turn[2];
+extern const char ashell_h[ SHELL_H_LEN ];
+extern const unsigned char aifile[ nsquare ];
+extern const unsigned char airank[ nsquare ];
+
+void pv_close( tree_t * restrict ptree, int ply, int type );
+void pv_copy( tree_t * restrict ptree, int ply );
+void set_derivative_param( void );
+void set_search_limit_time( int turn );
+void ehash_clear( void );
+void hash_store_pv( const tree_t * restrict ptree, unsigned int move,
+                   int turn );
+void check_futile_score_quies( const tree_t * restrict ptree,
+                              unsigned int move, int old_val, int new_val,
+                              int turn );
+void out_file( FILE *pf, const char *format, ... );
+void out_warning( const char *format, ... );
+void out_error( const char *format, ... );
+void show_prompt( void );
+void make_move_w( tree_t * restrict ptree, unsigned int move, int ply );
+void make_move_b( tree_t * restrict ptree, unsigned int move, int ply );
+void unmake_move_b( tree_t * restrict ptree, unsigned int move, int ply );
+void unmake_move_w( tree_t * restrict ptree, unsigned int move, int ply );
+void ini_rand( unsigned int s );
+void out_CSA( tree_t * restrict ptree, record_t *pr, unsigned int move );
+void out_pv( tree_t * restrict ptree, int value, int turn, unsigned int time );
+void hash_store( const tree_t * restrict ptree, int ply, int depth, int turn,
+                int value_type, int value, unsigned int move,
+                unsigned int state_node );
+void *memory_alloc( size_t nbytes );
+void unmake_move_root( tree_t * restrict ptree, unsigned int move );
+void add_rejections_root( tree_t * restrict ptree, unsigned int move_made );
+void sub_rejections_root( tree_t * restrict ptree, unsigned int move_made );
+void add_rejections( tree_t * restrict ptree, int turn, int ply );
+void sub_rejections( tree_t * restrict ptree, int turn, int ply );
+void adjust_time( unsigned int elapsed_new, int turn );
+int popu_count012( unsigned int u0, unsigned int u1, unsigned int u2 );
+int first_one012( unsigned int u0, unsigned int u1, unsigned int u2 );
+int last_one210( unsigned int u2, unsigned int u1, unsigned int u0 );
+int first_one01( unsigned int u0, unsigned int u1 );
+int first_one12( unsigned int u1, unsigned int u2 );
+int last_one01( unsigned int u0, unsigned int u1 );
+int last_one12( unsigned int u1, unsigned int u2 );
+int first_one1( unsigned int u1 );
+int first_one2( unsigned int u2 );
+int last_one0( unsigned int u0 );
+int last_one1( unsigned int u1 );
+int memory_free( void *p );
+int reset_time( unsigned int b_remain, unsigned int w_remain );
+int all_hash_learn_store( void );
+int gen_legal_moves( tree_t * restrict ptree, unsigned int *p0 );
+int rejections_probe( tree_t * restrict ptree, int turn, int ply );
+int ini( tree_t * restrict ptree );
+int fin( void );
+int ponder( tree_t * restrict ptree );
+int hash_learn( const tree_t * restrict ptree, unsigned int move, int value,
+               int depth );
+int book_on( void );
+int book_off( void );
+int hash_learn_on( void );
+int hash_learn_off( void );
+int is_move_check_b( const tree_t * restrict ptree, unsigned int move );
+int is_move_check_w( const tree_t * restrict ptree, unsigned int move );
+int solve_problems( tree_t * restrict ptree, unsigned int nposition );
+int read_board_rep1( const char *str_line, min_posi_t *pmin_posi );
+int com_turn_start( tree_t * restrict ptree, int flag );
+int read_record( tree_t * restrict ptree, const char *str_file,
+                unsigned int moves, int flag );
+int out_board( const tree_t * restrict ptree, FILE *pf, unsigned int move,
+              int flag );
+int make_root_move_list( tree_t * restrict ptree, int flag );
+int record_wind( record_t *pr );
+int book_probe( tree_t * restrict ptree );
+int detect_repetition( tree_t * restrict ptree, int ply, int turn, int nth );
+int is_mate( tree_t * restrict ptree, int ply );
+int is_mate_w_pawn_drop( tree_t * restrict ptree, int sq_drop );
+int is_mate_b_pawn_drop( tree_t * restrict ptree, int sq_drop );
+int clear_trans_table( void );
+int eval_max_score( const tree_t * restrict ptree, unsigned int move,
+                   int stand_pat, int turn, int diff );
+int estimate_score_diff( const tree_t * restrict ptree, unsigned int move,
+                        int turn );
+int eval_material( const tree_t * restrict ptree );
+int ini_trans_table( void );
+int is_hand_eq_supe( unsigned int u, unsigned int uref );
+int is_move_valid( tree_t * restrict ptree, unsigned int move, int turn );
+int is_hash_move_valid( tree_t * restrict ptree, unsigned int move, int turn );
+int iterate( tree_t * restrict ptree, int flag );
+int gen_next_move( tree_t * restrict ptree, int ply, int turn );
+int gen_next_evasion( tree_t * restrict ptree, int ply, int turn );
+int ini_game( tree_t * restrict ptree, const min_posi_t *pmin_posi, int flag,
+             const char *str_name1, const char *str_name2 );
+int open_history( const char *str_name1, const char *str_name2 );
+int next_cmdline( int is_wait );
+int procedure( tree_t * restrict ptree );
+int get_cputime( unsigned int *ptime );
+int get_elapsed( unsigned int *ptime );
+int interpret_CSA_move( tree_t * restrict ptree, unsigned int *pmove,
+                       const char *str );
+int in_CSA( tree_t * restrict ptree, record_t *pr, unsigned int *pmove,
+           int do_history );
+int in_CSA_record( FILE * restrict pf, tree_t * restrict ptree );
+int renovate_time( int turn );
+int exam_tree( const tree_t * restrict ptree );
+int rep_check_root( tree_t * restrict ptree );
+int make_move_root( tree_t * restrict ptree, unsigned int move, int flag );
+int search_quies( tree_t * restrict ptree, int alpha, int beta, int turn,
+                 int ply, int qui_ply );
+int search( tree_t * restrict ptree, int alpha, int beta, int turn,
+           int depth, int ply, unsigned int state_node );
+int searchr( tree_t * restrict ptree, int alpha, int beta, int turn,
+            int depth );
+int evaluate( tree_t * restrict ptree, int ply, int turn );
+int swap( const tree_t * restrict ptree, unsigned int move, int alpha,
+         int beta, int turn );
+int file_close( FILE *pf );
+int record_open( record_t *pr, const char *str_file,
+                record_mode_t record_mode, const char *str_name1,
+                const char *str_name2 );
+int record_close( record_t *pr );
+unsigned int phash( unsigned int move, int turn );
+unsigned int is_mate_in3ply( tree_t * restrict ptree, int turn, int ply );
+unsigned int is_b_mate_in_1ply( tree_t * restrict ptree );
+unsigned int is_w_mate_in_1ply( tree_t * restrict ptree );
+unsigned int hash_probe( tree_t * restrict ptree, int ply, int depth, int turn,
+                        int alpha, int beta, unsigned int state_node );
+unsigned int rand32( void );
+unsigned int is_black_attacked( const tree_t * restrict ptree, int sq );
+unsigned int is_white_attacked( const tree_t * restrict ptree, int sq );
+unsigned int is_pinned_on_black_king( const tree_t * restrict ptree,
+                                    int isquare, int idirec );
+unsigned int is_pinned_on_white_king( const tree_t * restrict ptree,
+                                    int isquare, int idirec );
+unsigned int *b_gen_captures( const tree_t * restrict ptree,
+                             unsigned int * restrict pmove );
+unsigned int *b_gen_nocaptures( const tree_t * restrict ptree,
+                               unsigned int * restrict pmove );
+unsigned int *b_gen_drop( tree_t * restrict ptree,
+                         unsigned int * restrict pmove );
+unsigned int *b_gen_evasion( tree_t *restrict ptree,
+                            unsigned int * restrict pmove );
+unsigned int *b_gen_checks( tree_t * restrict __ptree__,
+                           unsigned int * restrict pmove );
+unsigned int *b_gen_cap_nopro_ex2( const tree_t * restrict ptree,
+                                  unsigned int * restrict pmove );
+unsigned int *b_gen_nocap_nopro_ex2( const tree_t * restrict ptree,
+                                    unsigned int * restrict pmove );
+unsigned int *w_gen_captures( const tree_t * restrict ptree,
+                             unsigned int * restrict pmove );
+unsigned int *w_gen_nocaptures( const tree_t * restrict ptree,
+                               unsigned int * restrict pmove );
+unsigned int *w_gen_drop( tree_t * restrict ptree,
+                         unsigned int * restrict pmove );
+unsigned int *w_gen_evasion( tree_t * restrict ptree,
+                            unsigned int * restrict pmove );
+unsigned int *w_gen_checks( tree_t * restrict __ptree__,
+                           unsigned int * restrict pmove );
+unsigned int *w_gen_cap_nopro_ex2( const tree_t * restrict ptree,
+                                  unsigned int * restrict pmove );
+unsigned int *w_gen_nocap_nopro_ex2( const tree_t * restrict ptree,
+                                    unsigned int * restrict pmove );
+uint64_t hash_func( const tree_t * restrict ptree );
+uint64_t rand64( void );
+trans_entry_t hash_learn_store( const tree_t * restrict ptree, int depth,
+                                 int value, unsigned int move );
+FILE *file_open( const char *str_file, const char *str_mode );
+bitboard_t attacks_to_piece( const tree_t * restrict ptree, int sq );
+bitboard_t horse_attacks( const tree_t * restrict ptree, int i );
+const char *str_time( unsigned int time );
+const char *str_time_symple( unsigned int time );
+const char *str_CSA_move( unsigned int move );
+const char *str_CSA_move_plus( tree_t * restrict ptree, unsigned int move,
+                              int ply, int turn );
+
+#if defined(MPV)
+int root_mpv;
+int mpv_num;
+int mpv_width;
+pv_t mpv_pv[ MPV_MAX_PV*2 + 1 ];
+#endif
+
+#if defined(TLP)
+#  define SignKey(word2, word1) word2 ^= ( word1 )
+#  define TlpEnd()              tlp_end();
+#  if ! defined(_WIN32)
+extern pthread_attr_t pthread_attr;
+#  endif
+#  if defined(MNJ_LAN)
+uint64_t tlp_count_node( tree_t * restrict ptree );
+#  endif
+void tlp_yield( void );
+void tlp_set_abort( tree_t * restrict ptree );
+void lock( lock_t *plock );
+void unlock( lock_t *plock );
+void tlp_end( void );
+int tlp_search( tree_t * restrict ptree, int alpha, int beta, int turn,
+               int depth, int ply, unsigned int state_node );
+int tlp_split( tree_t * restrict ptree );
+int tlp_start( void );
+int tlp_is_descendant( const tree_t * restrict ptree, int slot_ancestor );
+int lock_init( lock_t *plock );
+int lock_free( lock_t *plock );
+extern lock_t tlp_lock;
+extern volatile int tlp_abort;
+extern volatile int tlp_idle;
+extern volatile int tlp_num;
+extern int tlp_max;
+extern int tlp_nsplit;
+extern int tlp_nabort;
+extern int tlp_nslot;
+extern SHARE unsigned short tlp_rejections_slot[ REJEC_MASK+1 ];
+extern tree_t tlp_atree_work[ TLP_NUM_WORK ];
+extern tree_t * volatile tlp_ptrees[ TLP_MAX_THREADS ];
+#else /* no TLP */
+#  define SignKey(word2, word1)
+#  define TlpEnd()
+extern tree_t tree;
+#endif
+
+#if ! defined(_WIN32)
+extern clock_t clk_tck;
+#endif
+
+#if ! defined(NDEBUG)
+int exam_bb( const tree_t *ptree );
+#endif
+
+#if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
+#  define Out( ... ) out( __VA_ARGS__ )
+void out( const char *format, ... );
+#else
+#  define Out( ... )
+#endif
+
+#if ! defined(NO_LOGGING)
+extern FILE *pf_log;
+extern const char *str_dir_logs;
+#endif
+
+#if defined(NO_STDOUT) || defined(WIN32_PIPE)
+#  define OutBeep()
+#  define StdoutStress(x,y) 1
+#  define StdoutNormal()    1
+#else
+#  define OutBeep()         out_beep()
+#  define StdoutStress(x,y) stdout_stress(x,y)
+#  define StdoutNormal()    stdout_normal()
+void out_beep( void );
+int stdout_stress( int is_promote, int ifrom );
+int stdout_normal( void );
+#endif
+
+#if defined(CSA_LAN) && defined(MNJ_LAN)
+#  define ShutdownClient sckt_shutdown( sckt_mnj ); \
+                         sckt_shutdown( sckt_csa ); \
+                         sckt_mnj = sckt_csa = SCKT_NULL
+#elif defined(CSA_LAN)
+#  define ShutdownClient sckt_shutdown( sckt_csa ); \
+                         sckt_csa = SCKT_NULL
+#elif defined(MNJ_LAN)
+#  define ShutdownClient sckt_shutdown( sckt_mnj );  \
+                         sckt_mnj = SCKT_NULL
+#else
+#  define ShutdownClient
+#endif
+
+#if defined(CSA_LAN) || defined(MNJ_LAN)
+int client_next_game( tree_t * restrict ptree, const char *str_addr,
+                     int iport );
+sckt_t sckt_connect( const char *str_addr, int iport );
+int sckt_shutdown( sckt_t sd );
+int sckt_check( sckt_t sd );
+int sckt_in( sckt_t sd, char *str, int n );
+int sckt_out( sckt_t sd, const char *fmt, ... );
+extern unsigned int time_last_send;
+#endif
+
+#if defined(CSA_LAN)
+extern int client_turn;
+extern int client_ngame;
+extern int client_max_game;
+extern long client_port;
+extern char client_str_addr[256];
+extern char client_str_id[256];
+extern char client_str_pwd[256];
+extern sckt_t sckt_csa;
+#endif
+
+#if defined(MNJ_LAN)
+#  define MnjOut( ... ) if ( sckt_mnj != SCKT_NULL ) \
+                          sckt_out( sckt_mnj, __VA_ARGS__ )
+extern short mnj_tbl[ MNJ_MASK + 1 ];
+extern sckt_t sckt_mnj;
+int mnj_reset_tbl( int sd, unsigned int seed );
+int analyze( tree_t * restrict ptree );
+int mnj_posi_id;
+unsigned int mnj_move_last;
+#else
+#  define MnjOut( ... )
+#endif
+
+
+#if defined(DEKUNOBOU) || defined(CSA_LAN) || defined(MNJ_LAN)
+const char *str_WSAError( const char *str );
+#endif
+
+#if defined(DEKUNOBOU) && defined(_WIN32)
+#  define OutDek( ... ) if ( dek_ngame ) { int i = dek_out( __VA_ARGS__ ); \
+                                         if ( i < 0 ) { return i; } }
+const char *str_WSAError( const char *str );
+int dek_start( const char *str_sddr, int port_dek, int port_bnz );
+int dek_next_game( tree_t * restrict ptree );
+int dek_in( char *str, int n );
+int dek_out( const char *format, ... );
+int dek_parse( char *str, int len );
+int dek_check( void );
+extern SOCKET dek_socket_in;
+extern SOCKET dek_s_accept;
+extern u_long dek_ul_addr;
+extern unsigned int dek_ngame;
+extern unsigned int dek_lost;
+extern unsigned int dek_win;
+extern int dek_turn;
+extern u_short dek_ns;
+#else
+#  define OutDek( ... )
+#endif
+
+#if defined(CSASHOGI)
+#  define OutCsaShogi( ... ) out_csashogi( __VA_ARGS__ )
+void out_csashogi( const char *format, ... );
+#else
+#  define OutCsaShogi( ... )
+#endif
+
+#define AttackBishop(bb,i)   BBOr( bb, AttackDiag1(i), AttackDiag2(i) )
+#define AttackRook(bb,i)     (bb) = AttackFile(i);                  \
+                             (bb).p[aslide[i].ir0] |= AttackRank(i)
+
+
+
+extern check_table_t b_chk_tbl[nsquare];
+extern check_table_t w_chk_tbl[nsquare];
+
+#if defined(DBG_EASY)
+extern unsigned int easy_move;
+#endif
+
+#if defined(MINIMUM)
+
+#  define MT_CAP_PAWN       ( DPawn      + DPawn )
+#  define MT_CAP_LANCE      ( DLance     + DLance )
+#  define MT_CAP_KNIGHT     ( DKnight    + DKnight )
+#  define MT_CAP_SILVER     ( DSilver    + DSilver )
+#  define MT_CAP_GOLD       ( DGold      + DGold )
+#  define MT_CAP_BISHOP     ( DBishop    + DBishop )
+#  define MT_CAP_ROOK       ( DRook      + DRook )
+#  define MT_CAP_PRO_PAWN   ( DProPawn   + DPawn )
+#  define MT_CAP_PRO_LANCE  ( DProLance  + DLance )
+#  define MT_CAP_PRO_KNIGHT ( DProKnight + DKnight )
+#  define MT_CAP_PRO_SILVER ( DProSilver + DSilver )
+#  define MT_CAP_HORSE      ( DHorse     + DBishop )
+#  define MT_CAP_DRAGON     ( DDragon    + DRook )
+#  define MT_CAP_KING       ( DKing      + DKing )
+#  define MT_PRO_PAWN       ( DProPawn   - DPawn )
+#  define MT_PRO_LANCE      ( DProLance  - DLance )
+#  define MT_PRO_KNIGHT     ( DProKnight - DKnight )
+#  define MT_PRO_SILVER     ( DProSilver - DSilver )
+#  define MT_PRO_BISHOP     ( DHorse     - DBishop )
+#  define MT_PRO_ROOK       ( DDragon    - DRook )
+
+#else
+
+#  define MT_CAP_PAWN       ( p_value_ex[ 15 + pawn ] )
+#  define MT_CAP_LANCE      ( p_value_ex[ 15 + lance ] )
+#  define MT_CAP_KNIGHT     ( p_value_ex[ 15 + knight ] )
+#  define MT_CAP_SILVER     ( p_value_ex[ 15 + silver ] )
+#  define MT_CAP_GOLD       ( p_value_ex[ 15 + gold ] )
+#  define MT_CAP_BISHOP     ( p_value_ex[ 15 + bishop ] )
+#  define MT_CAP_ROOK       ( p_value_ex[ 15 + rook ] )
+#  define MT_CAP_PRO_PAWN   ( p_value_ex[ 15 + pro_pawn ] )
+#  define MT_CAP_PRO_LANCE  ( p_value_ex[ 15 + pro_lance ] )
+#  define MT_CAP_PRO_KNIGHT ( p_value_ex[ 15 + pro_knight ] )
+#  define MT_CAP_PRO_SILVER ( p_value_ex[ 15 + pro_silver ] )
+#  define MT_CAP_HORSE      ( p_value_ex[ 15 + horse ] )
+#  define MT_CAP_DRAGON     ( p_value_ex[ 15 + dragon ] )
+#  define MT_CAP_KING       ( DKing + DKing )
+#  define MT_PRO_PAWN       ( benefit2promo[ 7 + pawn ] )
+#  define MT_PRO_LANCE      ( benefit2promo[ 7 + lance ] )
+#  define MT_PRO_KNIGHT     ( benefit2promo[ 7 + knight ] )
+#  define MT_PRO_SILVER     ( benefit2promo[ 7 + silver ] )
+#  define MT_PRO_BISHOP     ( benefit2promo[ 7 + bishop ] )
+#  define MT_PRO_ROOK       ( benefit2promo[ 7 + rook ] )
+
+void fill_param_zero( void );
+void ini_param( param_t *p );
+void add_param( param_t *p1, const param_t *p2 );
+void inc_param( const tree_t * restrict ptree, param_t * restrict pd,
+               double dinc );
+void param_sym( param_t *p );
+void renovate_param( const param_t *pd );
+int learn( tree_t * restrict ptree, int is_ini, int nsteps,
+          unsigned int max_games, int max_iterations,
+          int nworker1, int nworker2 );
+int record_setpos( record_t *pr, const rpos_t *prpos );
+int record_getpos( record_t *pr, rpos_t *prpos );
+int record_rewind( record_t *pr );
+int book_create( tree_t * restrict ptree );
+int hash_learn_create( void );
+int out_param( void );
+double calc_penalty( void );
+
+#endif /* no MINIMUM */
+
+#if ( REP_HIST_LEN - PLY_MAX ) < 1
+#  error "REP_HIST_LEN - PLY_MAX is too small."
+#endif
+
+#if defined(CSA_LAN) && '\n' != 0x0a
+#  error "'\n' is not the ASCII code of LF (0x0a)."
+#endif
+
+#endif /* SHOGI_H */
diff --git a/swap.c b/swap.c
new file mode 100644 (file)
index 0000000..a195364
--- /dev/null
+++ b/swap.c
@@ -0,0 +1,391 @@
+#include <stdlib.h>
+#include <limits.h>
+#include "shogi.h"
+
+int
+swap( const tree_t * restrict ptree, unsigned int move, int root_alpha,
+      int root_beta, int turn )
+{
+  bitboard_t bb, bb_temp, bb_attack;
+  unsigned int uattack;
+  int attacked_piece, from, to, nc, ir0;
+  int piece_cap, piece, value, xvalue, alpha, beta, is_promo;
+
+  from = (int)I2From( move );
+  to   = (int)I2To( move );
+
+  if ( from >= nsquare )
+    {
+      value          = 0;
+      piece          = From2Drop( from );
+      attacked_piece = p_value_ex[15+piece];
+    }
+  else {
+    piece     = (int)I2PieceMove( move );
+    piece_cap = (int)UToCap( move );
+    is_promo  = (int)I2IsPromote( move );
+    
+    value          = p_value_ex[15+piece_cap];
+    attacked_piece = p_value_ex[15+piece];
+    if ( is_promo )
+      {
+       value          += benefit2promo[7+piece];
+       attacked_piece += benefit2promo[7+piece];
+      }
+    xvalue = value - attacked_piece - MT_PRO_PAWN;
+    if ( xvalue >= root_beta ) { return xvalue; }
+  }
+
+  bb_attack = attacks_to_piece( ptree, to );
+  alpha     = INT_MIN;
+  beta      = value;
+  for ( nc = 1;; nc++ )
+    {
+      /* remove an attacker, and add a hidden piece to attack bitmap */
+      if ( from < nsquare )
+       {
+         Xor( from, bb_attack );
+         switch ( adirec[to][from] )
+           {
+           case direc_rank:
+             ir0     = aslide[from].ir0;
+             uattack = AttackRank( from );
+             if ( from > to ) { uattack &= abb_plus_rays[from].p[ir0]; }
+             else               { uattack &= abb_minus_rays[from].p[ir0]; }
+             uattack &= BB_B_RD.p[ir0] |  BB_W_RD.p[ir0];
+             bb_attack.p[ir0] |= uattack;
+             break;
+
+           case direc_file:
+             bb = AttackFile( from );
+             BBOr( bb_temp, BB_B_RD, BB_W_RD );
+             if ( from > to )
+               {
+                 BBOr( bb_temp, bb_temp, BB_BLANCE );
+                 BBAnd( bb, bb, abb_plus_rays[from] );
+               }
+             else {
+               BBOr( bb_temp, bb_temp, BB_WLANCE );
+               BBAnd( bb, bb, abb_minus_rays[from] );
+             }
+             BBAnd( bb, bb, bb_temp );
+             BBOr( bb_attack, bb_attack, bb );
+             break;
+             
+           case direc_diag1:
+             bb = AttackDiag1( from );
+             if ( from > to ) { BBAnd( bb, bb, abb_plus_rays[from] ); }
+             else               { BBAnd( bb, bb, abb_minus_rays[from] ); }
+             BBOr( bb_temp, BB_B_BH, BB_W_BH );
+             BBAnd( bb, bb, bb_temp );
+             BBOr( bb_attack, bb_attack, bb );
+             break;
+             
+           case direc_diag2:
+             bb = AttackDiag2( from );
+             if ( from > to ) { BBAnd( bb, bb, abb_plus_rays[from] ); }
+             else               { BBAnd( bb, bb, abb_minus_rays[from] ); }
+             BBOr( bb_temp, BB_B_BH, BB_W_BH );
+             BBAnd( bb, bb, bb_temp );
+             BBOr( bb_attack, bb_attack, bb );
+             break;
+             
+           }
+       }
+      if ( ! BBToU( bb_attack ) ) { break; }
+
+      /* find a cheapest piece attacking the target */
+      turn  = Flip( turn );
+      value = attacked_piece - value;
+      if ( turn )
+       {
+         if( BBContract( bb_attack, BB_WPAWN ) )
+           {
+             from           = to-nfile;
+             attacked_piece = MT_CAP_PAWN;
+             if ( to > 53 )
+               {
+                 value          += MT_PRO_PAWN;
+                 attacked_piece += MT_PRO_PAWN;
+               }
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WLANCE, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_LANCE;
+             if ( to > 53 )
+               {
+                 value          += MT_PRO_LANCE;
+                 attacked_piece += MT_PRO_LANCE;
+               }
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WKNIGHT, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_KNIGHT;
+             if ( to > 53 )
+               {
+                 value          += MT_PRO_KNIGHT;
+                 attacked_piece += MT_PRO_KNIGHT;
+               }
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WPRO_PAWN, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_PRO_PAWN;
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WPRO_LANCE, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_PRO_LANCE;
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WPRO_KNIGHT, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_PRO_KNIGHT;
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WSILVER, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from          = FirstOne( bb );
+             attacked_piece = MT_CAP_SILVER;
+             if ( from > 53 || to > 53 )
+               {
+                 value          += MT_PRO_SILVER;
+                 attacked_piece += MT_PRO_SILVER;
+               }
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WPRO_SILVER, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_PRO_SILVER;
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WGOLD, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_GOLD;
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WBISHOP, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_BISHOP;
+             if ( from > 53 || to > 53 )
+               {
+                 value          += MT_PRO_BISHOP;
+                 attacked_piece += MT_PRO_BISHOP;
+               }
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WHORSE, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_HORSE;
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WROOK, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_ROOK;
+             if ( from > 53 || to > 53 )
+               {
+                 value          += MT_PRO_ROOK;
+                 attacked_piece += MT_PRO_ROOK;
+               }
+             goto ab_cut;
+           }
+         BBAnd( bb, BB_WDRAGON, bb_attack );
+         if( BBToU( bb ) )
+           {
+             from           = FirstOne( bb );
+             attacked_piece = MT_CAP_DRAGON;
+             goto ab_cut;
+           }
+         if( BBContract( bb_attack, BB_WKING ) )
+           {
+             from           = SQ_WKING;
+             attacked_piece = MT_CAP_KING;
+             goto ab_cut;
+           }
+       }
+      else {
+       if( BBContract( bb_attack, BB_BPAWN ) )
+         {
+           from           = to+nfile;
+           attacked_piece = MT_CAP_PAWN;
+           if ( to < 27 )
+             {
+               value          += MT_PRO_PAWN;
+               attacked_piece += MT_PRO_PAWN;
+             }
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BLANCE, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_LANCE;
+           if ( to < 27 )
+             {
+               value          += MT_PRO_LANCE;
+               attacked_piece += MT_PRO_LANCE;
+             }
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BKNIGHT, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_KNIGHT;
+           if ( to < 27 )
+             {
+               value          += MT_PRO_KNIGHT;
+               attacked_piece += MT_PRO_KNIGHT;
+             }
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BPRO_PAWN, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_PRO_PAWN;
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BPRO_LANCE, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_PRO_LANCE;
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BPRO_KNIGHT, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_PRO_KNIGHT;
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BSILVER, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_SILVER;
+           if ( from < 27 || to < 27 )
+             {
+               value          += MT_PRO_SILVER;
+               attacked_piece += MT_PRO_SILVER;
+             }
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BPRO_SILVER, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_PRO_SILVER;
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BGOLD, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_GOLD;
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BBISHOP, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from          = FirstOne( bb );
+           attacked_piece = MT_CAP_BISHOP;
+           if ( from < 27 || to < 27 )
+             {
+               value          += MT_PRO_BISHOP;
+               attacked_piece += MT_PRO_BISHOP;
+             }
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BHORSE, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_HORSE;
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BROOK, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_ROOK;
+           if ( from < 27 || to < 27 )
+             {
+               value          += MT_PRO_ROOK;
+               attacked_piece += MT_PRO_ROOK;
+             }
+           goto ab_cut;
+         }
+       BBAnd( bb, BB_BDRAGON, bb_attack );
+       if( BBToU( bb ) )
+         {
+           from           = FirstOne( bb );
+           attacked_piece = MT_CAP_DRAGON;
+           goto ab_cut;
+         }
+       if( BBContract( bb_attack, BB_BKING ) )
+         {
+           from           = SQ_BKING;
+           attacked_piece = MT_CAP_KING;
+           goto ab_cut;
+         }
+      }
+      break;
+
+    ab_cut:
+      if ( nc & 1 )
+       {
+         if ( -value > alpha )
+           {
+             if ( -value >= beta )      { return beta; }
+             if ( -value >= root_beta ) { return -value; }
+             alpha = -value;
+           }
+         else {
+           xvalue = attacked_piece + MT_PRO_PAWN - value;
+           if ( xvalue <= alpha )      { return alpha; }
+           if ( xvalue <= root_alpha ) { return xvalue; }
+         }
+       }
+      else {
+       if ( value < beta )
+         {
+           if ( value <= alpha )      { return alpha; }
+           if ( value <= root_alpha ) { return value; }
+           beta = value;
+         }
+       else {
+         xvalue = value - attacked_piece - MT_PRO_PAWN;
+         if ( xvalue >= beta )      { return beta; }
+         if ( xvalue >= root_beta ) { return xvalue; }
+       }
+      }
+    }
+
+  if ( nc & 1 ) { return beta; }
+  else          { return alpha; }
+}
diff --git a/thread.c b/thread.c
new file mode 100644 (file)
index 0000000..c88461a
--- /dev/null
+++ b/thread.c
@@ -0,0 +1,458 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_WIN32)
+#  include <process.h>
+#else
+#  include <sched.h>
+#endif
+#include "shogi.h"
+
+#if defined(TLP)
+
+#  if defined(_WIN32)
+static unsigned int __stdcall start_address( void *arg );
+#  else
+static void *start_address( void *arg );
+#  endif
+
+static tree_t *find_child( void );
+static void init_state( const tree_t * restrict parent,
+                       tree_t * restrict child );
+static void copy_state( tree_t * restrict parent,
+                       const tree_t * restrict child, int value );
+static void wait_work( int tid, tree_t *parent );
+
+int
+tlp_start( void )
+{
+  int work[ TLP_MAX_THREADS ];
+  int num;
+
+  if ( tlp_num ) { return 1; }
+
+  for ( num = 1; num < tlp_max; num++ )
+    {
+      work[num] = num;
+      
+#  if defined(_WIN32)
+      if ( ! _beginthreadex( 0, 0, start_address, work+num, 0, 0 ) )
+       {
+         str_error = "_beginthreadex() failed.";
+         return -2;
+       }
+#  else
+      {
+       pthread_t pt;
+       if ( pthread_create( &pt, &pthread_attr, start_address, work+num ) )
+         {
+           str_error = "pthread_create() failed.";
+           return -2;
+         }
+      }
+#  endif
+    }
+  while ( tlp_num +1 < tlp_max ) { tlp_yield(); }
+
+  return 1;
+}
+
+
+void
+tlp_end( void )
+{
+  tlp_abort = 1;
+  while ( tlp_num ) { tlp_yield(); }
+  tlp_abort = 0;
+}
+
+
+int
+tlp_split( tree_t * restrict ptree )
+{
+  tree_t *child;
+  int num, nchild, i;
+
+  lock( &tlp_lock );
+
+  if ( ! tlp_idle || ptree->tlp_abort )
+    {
+      unlock( &tlp_lock );
+      return 0;
+    }
+
+  tlp_ptrees[ ptree->tlp_id ] = NULL;
+  ptree->tlp_nsibling         = 0;
+  nchild                      = 0;
+  for ( num = 0; num < tlp_max; num++ )
+    {
+      if ( tlp_ptrees[num] ) { ptree->tlp_ptrees_sibling[num] = 0; }
+      else {
+       child = find_child();
+       if ( ! child ) { continue; }
+
+       nchild += 1;
+
+       for ( i=0; i<tlp_max; i++ ) { child->tlp_ptrees_sibling[i] = NULL; }
+       child->tlp_ptree_parent        = ptree;
+       child->tlp_id                  = (unsigned char)num;
+       child->tlp_used                = 1;
+       child->tlp_abort               = 0;
+       ptree->tlp_ptrees_sibling[num] = child;
+       ptree->tlp_nsibling           += 1;
+       init_state( ptree, child );
+
+       tlp_ptrees[num] = child;
+      }
+    }
+
+  if ( ! nchild )
+    {
+      tlp_ptrees[ ptree->tlp_id ] = ptree;
+      unlock( &tlp_lock );
+      return 0;
+    }
+  
+  tlp_nsplit += 1;
+  tlp_idle   += 1;
+
+  unlock( &tlp_lock );
+  
+  wait_work( ptree->tlp_id, ptree );
+
+  return 1;
+}
+
+
+void
+tlp_set_abort( tree_t * restrict ptree )
+{
+  int num;
+
+  ptree->tlp_abort = 1;
+  for ( num = 0; num < tlp_max; num++ )
+    if ( ptree->tlp_ptrees_sibling[num] )
+      {
+       tlp_set_abort( ptree->tlp_ptrees_sibling[num] );
+      }
+}
+
+
+#if defined(MNJ_LAN)
+uint64_t
+tlp_count_node( tree_t * restrict ptree )
+{
+  uint64_t uret = ptree->node_searched;
+  int num;
+
+  for ( num = 0; num < tlp_max; num++ )
+    if ( ptree->tlp_ptrees_sibling[num] )
+      {
+       uret += tlp_count_node( ptree->tlp_ptrees_sibling[num] );
+      }
+
+  return uret;
+}
+#endif
+
+
+int
+tlp_is_descendant( const tree_t * restrict ptree, int slot_ancestor )
+{
+  int slot = (int)ptree->tlp_slot;
+
+  for ( ;; ) {
+    if ( slot == slot_ancestor ) { return 1; }
+    else if ( ! slot )           { return 0; }
+    else { slot = tlp_atree_work[slot].tlp_ptree_parent->tlp_slot; }
+  }
+}
+
+
+int
+lock_init( lock_t *plock )
+{
+#  if defined(_MSC_VER)
+  *plock = 0;
+#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+  *plock = 0;
+#  else
+  if ( pthread_mutex_init( plock, 0 ) )
+    {
+      str_error = "pthread_mutex_init() failed.";
+      return -1;
+    }
+#  endif
+  return 1;
+}
+
+
+int
+lock_free( lock_t *plock )
+{
+#  if defined(_MSC_VER)
+  *plock = 0;
+#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+  *plock = 0;
+#  else
+  if ( pthread_mutex_destroy( plock ) )
+    {
+      str_error = "pthread_mutex_destroy() failed.";
+      return -1;
+    }
+#  endif
+  return 1;
+}
+
+
+void
+unlock( lock_t *plock )
+{
+#  if defined(_MSC_VER)
+  *plock = 0;
+#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+  *plock = 0;
+#  else
+  pthread_mutex_unlock( plock );
+#  endif
+}
+
+
+void
+lock( lock_t *plock )
+{
+#  if defined(_MSC_VER)
+  long l;
+
+  for ( ;; )
+    {
+      l = _InterlockedExchange( (void *)plock, 1 );
+      if ( ! l ) { return; }
+      while ( *plock );
+    }
+#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+  int itemp;
+
+  for ( ;; )
+    {
+      asm ( "1:   movl     $1,  %1 \n\t"
+           "     xchgl   (%0), %1 \n\t"
+           : "=g" (plock), "=r" (itemp) : "0" (plock) );
+      if ( ! itemp ) { return; }
+      while ( *plock );
+    }
+#  else
+  pthread_mutex_lock( plock );
+#  endif
+}
+
+
+void
+tlp_yield( void )
+{
+#if defined(_WIN32)
+  Sleep( 0 );
+#else
+  sched_yield();
+#endif
+}
+
+
+#  if defined(_MSC_VER)
+static unsigned int __stdcall start_address( void *arg )
+#  else
+static void *start_address( void *arg )
+#endif
+{
+  int tid = *(int *)arg;
+
+  tlp_ptrees[tid] = NULL;
+
+  lock( &tlp_lock );
+  Out( "Hi from thread no.%d\n", tid );
+  tlp_num  += 1;
+  tlp_idle += 1;
+  unlock( &tlp_lock );
+
+  wait_work( tid, NULL );
+
+  lock( &tlp_lock );
+  Out( "Bye from thread no.%d\n", tid );
+  tlp_num  -= 1;
+  tlp_idle -= 1;
+  unlock( &tlp_lock );
+
+  return 0;
+}
+
+
+static void
+wait_work( int tid, tree_t *parent )
+{
+  tree_t *slot;
+  int value;
+
+  for ( ;; ) {
+
+    for ( ;; ) {
+      if ( tlp_ptrees[tid] )                  { break; }
+      if ( parent && ! parent->tlp_nsibling ) { break; }
+      if ( tlp_abort )                        { return; }
+
+      tlp_yield();
+    }
+
+    lock( &tlp_lock );
+    if ( ! tlp_ptrees[tid] ) { tlp_ptrees[tid] = parent; }
+    tlp_idle -= 1;
+    unlock( &tlp_lock );
+
+    slot = tlp_ptrees[tid];
+    if ( slot == parent ) { return; }
+
+    value = tlp_search( slot,
+                       slot->tlp_ptree_parent->tlp_best,
+                       slot->tlp_ptree_parent->tlp_beta,
+                       slot->tlp_ptree_parent->tlp_turn,
+                       slot->tlp_ptree_parent->tlp_depth,
+                       slot->tlp_ptree_parent->tlp_ply,
+                       slot->tlp_ptree_parent->tlp_state_node );
+    
+    lock( &tlp_lock );
+    copy_state( slot->tlp_ptree_parent, slot, value );
+    slot->tlp_ptree_parent->tlp_nsibling            -= 1;
+    slot->tlp_ptree_parent->tlp_ptrees_sibling[tid]  = NULL;
+    slot->tlp_used   = 0;
+    tlp_ptrees[tid]  = NULL;
+    tlp_idle        += 1;
+    unlock( &tlp_lock);
+  }
+}
+
+
+static tree_t *
+find_child( void )
+{
+  int i;
+
+  for ( i = 1; i < TLP_NUM_WORK && tlp_atree_work[i].tlp_used; i++ );
+  if ( i == TLP_NUM_WORK ) { return NULL; }
+  if ( i > tlp_nslot ) { tlp_nslot = i; }
+
+  return tlp_atree_work + i;
+}
+
+
+static void
+init_state( const tree_t * restrict parent, tree_t * restrict child )
+{
+  int i, ply;
+
+  child->posi                  = parent->posi;
+  child->node_searched         = 0;
+  child->null_pruning_done     = 0;
+  child->null_pruning_tried    = 0;
+  child->check_extension_done  = 0;
+  child->recap_extension_done  = 0;
+  child->onerp_extension_done  = 0;
+  child->neval_called          = 0;
+  child->nquies_called         = 0;
+  child->nfour_fold_rep        = 0;
+  child->nperpetual_check      = 0;
+  child->nsuperior_rep         = 0;
+  child->nrep_tried            = 0;
+  child->nreject_tried         = 0;
+  child->nreject_done          = 0;
+  child->ntrans_always_hit     = 0;
+  child->ntrans_prefer_hit     = 0;
+  child->ntrans_probe          = 0;
+  child->ntrans_exact          = 0;
+  child->ntrans_lower          = 0;
+  child->ntrans_upper          = 0;
+  child->ntrans_superior_hit   = 0;
+  child->ntrans_inferior_hit   = 0;
+  child->fail_high             = 0;
+  child->fail_high_first       = 0;
+  ply = parent->tlp_ply;
+
+  child->anext_move[ply].value_cap1 = parent->anext_move[ply].value_cap1;
+  child->anext_move[ply].value_cap2 = parent->anext_move[ply].value_cap2;
+  child->anext_move[ply].move_cap1  = parent->anext_move[ply].move_cap1;
+  child->anext_move[ply].move_cap2  = parent->anext_move[ply].move_cap2;
+
+  child->move_last[ply]        = child->amove;
+  child->stand_pat[ply]        = parent->stand_pat[ply];
+  child->current_move[ply-1]   = parent->current_move[ply-1];
+  child->nsuc_check[ply-1]     = parent->nsuc_check[ply-1];
+  child->nsuc_check[ply]       = parent->nsuc_check[ply];
+
+  memcpy( child->hist_good,  parent->hist_good,  sizeof(parent->hist_good) );
+  memcpy( child->hist_tried, parent->hist_tried, sizeof(parent->hist_tried) );
+
+  for ( i = 0; i < root_nrep + ply - 1; i++ )
+    {
+      child->rep_board_list[i] = parent->rep_board_list[i];
+      child->rep_hand_list[i]  = parent->rep_hand_list[i];
+    }
+  for ( i = ply; i < PLY_MAX; i++ )
+    {
+      child->amove_killer[i] = parent->amove_killer[i];
+      child->killers[i]      = parent->killers[i];
+    }
+
+}
+
+
+static void
+copy_state( tree_t * restrict parent, const tree_t * restrict child,
+           int value )
+{
+  int i, ply;
+
+  parent->check_extension_done += child->check_extension_done;
+  parent->recap_extension_done += child->recap_extension_done;
+
+  if ( ! child->node_searched ) { return; }
+
+  parent->node_searched        += child->node_searched;
+  parent->null_pruning_done    += child->null_pruning_done;
+  parent->null_pruning_tried   += child->null_pruning_tried;
+  parent->onerp_extension_done += child->onerp_extension_done;
+  parent->neval_called         += child->neval_called;
+  parent->nquies_called        += child->nquies_called;
+  parent->nrep_tried           += child->nrep_tried;
+  parent->nfour_fold_rep       += child->nfour_fold_rep;
+  parent->nperpetual_check     += child->nperpetual_check;
+  parent->nsuperior_rep        += child->nsuperior_rep;
+  parent->nreject_tried        += child->nreject_tried;
+  parent->nreject_done         += child->nreject_done;
+  parent->ntrans_always_hit    += child->ntrans_always_hit;
+  parent->ntrans_prefer_hit    += child->ntrans_prefer_hit;
+  parent->ntrans_probe         += child->ntrans_probe;
+  parent->ntrans_exact         += child->ntrans_exact;
+  parent->ntrans_lower         += child->ntrans_lower;
+  parent->ntrans_upper         += child->ntrans_upper;
+  parent->ntrans_superior_hit  += child->ntrans_superior_hit;
+  parent->ntrans_inferior_hit  += child->ntrans_inferior_hit;
+  parent->fail_high_first      += child->fail_high_first;
+  parent->fail_high            += child->fail_high;
+
+  if ( child->tlp_abort || value <= parent->tlp_best ) { return; }
+
+  ply                       = parent->tlp_ply;
+  parent->tlp_best          = (short)value;
+  parent->pv[ply]           = child->pv[ply];
+  parent->current_move[ply] = child->current_move[ply];
+  
+  memcpy( parent->hist_tried, child->hist_tried, sizeof(child->hist_tried) );
+  memcpy( parent->hist_good,  child->hist_good,  sizeof(child->hist_good) );
+
+  for ( i = ply; i < PLY_MAX; i++ ) 
+    {
+      parent->amove_killer[i] = child->amove_killer[i];
+      parent->killers[i]      = child->killers[i];
+    }
+}
+
+
+#endif /* TLP */
diff --git a/time.c b/time.c
new file mode 100644 (file)
index 0000000..203c3bf
--- /dev/null
+++ b/time.c
@@ -0,0 +1,300 @@
+#include <limits.h>
+#include <assert.h>
+#if ! defined(_WIN32)
+#  include <sys/time.h>
+#  include <time.h>
+#endif
+#include "shogi.h"
+
+
+void
+set_search_limit_time( int turn )
+/*
+  [inputs]
+  global variables:
+    sec_limit       time limit of a side for an entire game in seconds
+    sec_limit_up    time limit for a move when the ordinary time has run out.
+                    the time is known as 'byo-yomi'.
+    sec_b_total     seconds spent by black 
+    sec_w_total     seconds spent by white
+    time_response
+    ( game_status & flag_puzzling )        time-control for puzzling-search
+    ( game_status & flag_pondering )       time-control for pondering-search
+    ( game_status & flag_time_extendable ) bonanza isn't punctual to the time
+  
+  argument:
+    turn            a side to move
+  
+  [outputs]
+  global variables:
+    time_limit      tentative deadline for searching in millisecond
+    time_max_limit  maximum allowed time to search in millisecond
+  
+  [working area]
+  local variables:
+    sec_elapsed     second spent by the side to move
+    sec_left        time left for the side in seconds
+    u0              tentative deadline for searching in second
+    u1              maximum allowed time to search in second
+*/
+{
+  unsigned int u0, u1;
+
+  /* no time-control */
+  if ( sec_limit_up == UINT_MAX || ( game_status & flag_pondering ) )
+    {
+      time_max_limit = time_limit = UINT_MAX;
+      return;
+    }
+  
+  /* not punctual to the time */
+  if ( ! sec_limit && ( game_status & flag_time_extendable ) )
+    {
+      u0 = sec_limit_up;
+      u1 = sec_limit_up * 5U;
+    }
+  /* have byo-yomi */
+  else if ( sec_limit_up )
+    {
+      unsigned int umax, umin, sec_elapsed, sec_left;
+
+      sec_elapsed = turn ? sec_w_total : sec_b_total;
+      sec_left    = ( sec_elapsed <= sec_limit ) ? sec_limit - sec_elapsed : 0;
+      u0          = ( sec_left + ( TC_NMOVE / 2U ) ) / TC_NMOVE;
+
+      /*
+       t = 2s is not beneficial since 2.8s are almost the same as 1.8s.
+        So that, we rather want to use up the ordinary time.
+      */
+      if ( u0 == 2U ) { u0 = 3U; }
+
+      /* 'byo-yomi' is so long that the ordinary time-limit is negligible. */
+      if ( u0 < sec_limit_up * 3U / 2U ) { u0 = sec_limit_up * 3U / 2U; }
+    
+      u1 = u0 * 5U;
+
+      umax = sec_left + sec_limit_up;
+      umin = 1;
+
+      if ( umax < u0 ) { u0 = umax; }
+      if ( umax < u1 ) { u1 = umax; }
+      if ( umin > u0 ) { u0 = umin; }
+      if ( umin > u1 ) { u1 = umin; }
+    }
+  /* no byo-yomi */
+  else {
+    unsigned int sec_elapsed, sec_left;
+    
+    sec_elapsed = turn ? sec_w_total : sec_b_total;
+
+    /* We have some seconds left to think. */
+    if ( sec_elapsed + SEC_MARGIN < sec_limit )
+      {
+       sec_left = sec_limit - sec_elapsed;
+       u0       = ( sec_left + ( TC_NMOVE / 2U ) ) / TC_NMOVE;
+       
+       /* t = 2s is not beneficial since 2.8s is almost the same as 1.8s. */
+       /* So that, we rather want to save the time.                       */
+       if ( u0 == 2U ) { u0 = 1U; }
+       u1 = u0 * 5U;
+      }
+    /* We are running out of time... */
+    else { u0 = u1 = 1U; }
+  }
+  
+  time_limit     = u0 * 1000U + 1000U - time_response;
+  time_max_limit = u1 * 1000U + 1000U - time_response;
+  
+  if ( game_status & flag_puzzling )
+    {
+      time_max_limit = time_max_limit / 5U;
+      time_limit     = time_max_limit / 5U;
+    }
+
+  Out( "- time ctrl: %u -- %u\n", time_limit, time_max_limit );
+}
+
+
+int
+renovate_time( int turn )
+{
+  unsigned int te, time_elapsed;
+  int iret;
+
+  iret = get_elapsed( &te );
+  if ( iret < 0 ) { return iret; }
+
+  time_elapsed = te - time_turn_start;
+  sec_elapsed  = time_elapsed / 1000U;
+  if ( ! sec_elapsed ) { sec_elapsed = 1U; }
+
+  if ( turn ) { sec_w_total += sec_elapsed; }
+  else        { sec_b_total += sec_elapsed; }
+  
+  time_turn_start = te;
+
+  return 1;
+}
+
+
+void
+adjust_time( unsigned int elapsed_new, int turn )
+{
+  const char *str = "TIME SKEW DETECTED";
+
+  if ( turn )
+    {
+      if ( sec_w_total + elapsed_new < sec_elapsed )
+       {
+         out_warning( str );
+         sec_w_total = 0;
+       }
+      else { sec_w_total = sec_w_total + elapsed_new - sec_elapsed; };
+    }
+  else {
+    if ( sec_b_total + elapsed_new < sec_elapsed )
+      {
+       out_warning( str );
+       sec_b_total = 0;
+      }
+    else { sec_b_total = sec_b_total + elapsed_new - sec_elapsed; };
+  }
+}
+
+
+int
+reset_time( unsigned int b_remain, unsigned int w_remain )
+{
+  if ( sec_limit_up == UINT_MAX )
+    {
+      str_error = "no time limit is set";
+      return -2;
+    }
+
+  if ( b_remain > sec_limit || w_remain > sec_limit )
+    {
+      snprintf( str_message, SIZE_MESSAGE,
+               "time remaining can't be larger than %u", sec_limit );
+      str_error = str_message;
+      return -2;
+    }
+
+  sec_b_total = sec_limit - b_remain;
+  sec_w_total = sec_limit - w_remain;
+  Out( "  elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
+
+  return 1;
+}
+
+
+const char *
+str_time( unsigned int time )
+{
+  static char str[32];
+  unsigned int time_min = time / 60000;
+  unsigned int time_sec = time / 1000;
+  unsigned int time_mil = time % 1000;
+
+  if ( time_min < 60 )
+    {
+      snprintf( str, 32, "%02u:%02u.%02u",
+               time_min, time_sec%60, time_mil/10 );
+    }
+  else {
+    snprintf( str, 32, "%02u:%02u:%02u.%02u",
+             time_min / 60, time_min % 60, time_sec%60, time_mil/10 );
+  }
+  return str;
+}
+
+
+const char *
+str_time_symple( unsigned int time )
+{
+  static char str[32];
+  unsigned int time_min = time / 60000;
+  unsigned int time_sec = time / 1000;
+  unsigned int time_mil = time % 1000;
+
+  if ( time_min == 0 )
+    {
+      snprintf( str, 32, "%5.2f", (float)(time_sec*1000+time_mil)/1000.0 );
+    }
+  else { snprintf( str, 32, "%2u:%02u", time_min, time_sec % 60 ); }
+
+  return str;
+}
+
+
+int
+get_cputime( unsigned int *ptime )
+{
+#if defined(_WIN32)
+  HANDLE         hProcess;
+  FILETIME       CreationTime, ExitTime, KernelTime, UserTime;
+  ULARGE_INTEGER uli_temp;
+
+  hProcess = GetCurrentProcess();
+  if ( GetProcessTimes( hProcess, &CreationTime, &ExitTime,
+                       &KernelTime, &UserTime ) )
+    {
+      uli_temp.LowPart  = UserTime.dwLowDateTime;
+      uli_temp.HighPart = UserTime.dwHighDateTime;
+      *ptime = (unsigned int)( uli_temp.QuadPart / 10000 );
+    }
+  else {
+#  if 0 /* winnt */
+    str_error = "GetProcessTimes() failed.";
+    return -1;
+#  else /* win95 */
+    *ptime = 0U;
+#  endif
+  }
+#else
+  clock_t clock_temp;
+  struct tms t;
+
+  if ( times( &t ) == -1 )
+    {
+      str_error = "times() faild.";
+      return -1;
+    }
+  clock_temp = t.tms_utime + t.tms_stime + t.tms_cutime + t.tms_cstime;
+  *ptime  = (unsigned int)( clock_temp / clk_tck ) * 1000;
+  clock_temp %= clk_tck;
+  *ptime += (unsigned int)( (clock_temp * 1000) / clk_tck );
+#endif /* no _WIN32 */
+  
+  return 1;
+}
+
+
+int
+get_elapsed( unsigned int *ptime )
+{
+#if defined(_WIN32)
+  /*
+    try timeBeginPeriod() and timeGetTime(),
+    or QueryPerformanceFrequency and QueryPerformanceCounter()
+  */
+  FILETIME       FileTime;
+  ULARGE_INTEGER uli_temp;
+
+  GetSystemTimeAsFileTime( &FileTime );
+  uli_temp.LowPart  = FileTime.dwLowDateTime;
+  uli_temp.HighPart = FileTime.dwHighDateTime;
+  *ptime            = (unsigned int)( uli_temp.QuadPart / 10000U );
+#else
+  struct timeval timeval;
+
+  if ( gettimeofday( &timeval, NULL ) == -1 )
+    {
+      str_error = "gettimeofday() faild.";
+      return -1;
+    }
+  *ptime  = (unsigned int)timeval.tv_sec * 1000;
+  *ptime += (unsigned int)timeval.tv_usec / 1000;
+#endif /* no _WIN32 */
+
+  return 1;
+}
diff --git a/unmake.c b/unmake.c
new file mode 100644 (file)
index 0000000..91e363d
--- /dev/null
+++ b/unmake.c
@@ -0,0 +1,326 @@
+#include <assert.h>
+#include "shogi.h"
+
+
+#define CapW( PIECE, piece, pro_piece )  Xor( to, BB_W ## PIECE );           \
+                                         HAND_B      -= flag_hand_ ## piece; \
+                                         BOARD[to]  = -pro_piece
+
+#define CapB( PIECE, piece, pro_piece )  Xor( to, BB_B ## PIECE );           \
+                                         HAND_W      -= flag_hand_ ## piece; \
+                                         BOARD[to]  = pro_piece
+
+#define NocapNopro( PIECE, piece )  SetClear( BB_ ## PIECE ); \
+                                    BOARD[from] = piece 
+
+#define NocapPro( PIECE , PRO_PIECE, piece )  Xor( from, BB_ ## PIECE );     \
+                                              Xor( to,   BB_ ## PRO_PIECE ); \
+                                              BOARD[from] = piece
+
+
+void
+unmake_move_b( tree_t * restrict ptree, unsigned int move, int ply )
+{
+  int from = (int)I2From(move);
+  int to   = (int)I2To(move);
+  int nrep = root_nrep + ply - 1;
+
+  HASH_KEY = ptree->rep_board_list[nrep];
+  MATERIAL = ptree->save_material[ply];
+
+  if ( from >= nsquare )
+    {
+      switch( From2Drop(from) )
+       {
+       case pawn:    Xor( to, BB_BPAWN );
+                      Xor( to-nfile, BB_BPAWN_ATK );
+                      HAND_B += flag_hand_pawn;     break;
+       case lance:   Xor( to, BB_BLANCE );
+                      HAND_B += flag_hand_lance;    break;
+       case knight:  Xor( to, BB_BKNIGHT );
+                      HAND_B += flag_hand_knight;   break;
+       case silver:  Xor( to, BB_BSILVER );
+                      HAND_B += flag_hand_silver;   break;
+       case gold:    Xor( to, BB_BGOLD );
+                      Xor( to, BB_BTGOLD );
+                      HAND_B += flag_hand_gold;     break;
+       case bishop:  Xor( to, BB_BBISHOP );
+                      Xor( to, BB_B_BH );
+                      HAND_B += flag_hand_bishop;   break;
+       default:      assert( From2Drop(from) == rook );
+                      Xor( to, BB_BROOK );
+                      Xor( to, BB_B_RD );
+                      HAND_B += flag_hand_rook;  break;
+       }
+
+      BOARD[to] = empty;
+      Xor( to, BB_BOCCUPY );
+      XorFile( to, OCCUPIED_FILE );
+      XorDiag2( to, OCCUPIED_DIAG2 );
+      XorDiag1( to, OCCUPIED_DIAG1 );
+    }
+  else {
+    const int ipiece_move = (int)I2PieceMove(move);
+    const int ipiece_cap  = (int)UToCap(move);
+    const int is_promote  = (int)I2IsPromote(move);
+    bitboard_t bb_set_clear;
+
+    BBOr( bb_set_clear, abb_mask[from], abb_mask[to] );
+    SetClear( BB_BOCCUPY );
+
+    if ( is_promote ) switch( ipiece_move )
+      {
+      case pawn:    NocapPro( BPAWN, BPRO_PAWN, pawn );
+                    Xor( to, BB_BPAWN_ATK );
+                    Xor( to, BB_BTGOLD );                        break;
+      case lance:   NocapPro( BLANCE,  BPRO_LANCE, lance );
+                    Xor( to, BB_BTGOLD );                        break;
+      case knight:  NocapPro( BKNIGHT, BPRO_KNIGHT, knight );
+                    Xor( to, BB_BTGOLD );                        break;
+      case silver:  NocapPro( BSILVER, BPRO_SILVER, silver );
+                    Xor( to, BB_BTGOLD );                        break;
+      case bishop:  NocapPro( BBISHOP, BHORSE, bishop );
+                    Xor( to, BB_B_HDK );
+                   SetClear( BB_B_BH );                         break;
+      default:      assert( ipiece_move == rook );
+                    NocapPro( BROOK, BDRAGON, rook );
+                    Xor( to, BB_B_HDK );
+                   SetClear( BB_B_RD );                         break;
+      }
+    else switch ( ipiece_move )
+      {
+      case pawn:       NocapNopro( BPAWN, pawn );
+                        Xor( to-nfile, BB_BPAWN_ATK );
+                        Xor( to,       BB_BPAWN_ATK );          break;
+      case lance:       NocapNopro( BLANCE,  lance );           break;
+      case knight:      NocapNopro( BKNIGHT, knight );          break;
+      case silver:      NocapNopro( BSILVER, silver );          break;
+      case gold:        NocapNopro( BGOLD, gold );
+                        SetClear( BB_BTGOLD );                  break;
+      case bishop:      NocapNopro( BBISHOP, bishop );
+                        SetClear( BB_B_BH );                    break;
+      case rook:        NocapNopro( BROOK, rook);
+                        SetClear( BB_B_RD );                    break;
+      case king:       BOARD[from] = king;
+                        SQ_BKING    = (char)from;
+                        SetClear( BB_B_HDK );                   break;
+      case pro_pawn:    NocapNopro( BPRO_PAWN, pro_pawn );
+                        SetClear( BB_BTGOLD );                  break;
+      case pro_lance:   NocapNopro( BPRO_LANCE,  pro_lance );
+                        SetClear( BB_BTGOLD );                  break;
+      case pro_knight:  NocapNopro( BPRO_KNIGHT, pro_knight );
+                        SetClear( BB_BTGOLD );                  break;
+      case pro_silver:  NocapNopro( BPRO_SILVER, pro_silver );
+                        SetClear( BB_BTGOLD );                  break;
+      case horse:      NocapNopro( BHORSE, horse );
+                        SetClear( BB_B_HDK );
+                        SetClear( BB_B_BH );                    break;
+      default:          assert( ipiece_move == dragon );
+                        NocapNopro( BDRAGON, dragon );
+                        SetClear( BB_B_HDK );
+                        SetClear( BB_B_RD );                    break;
+      }
+
+    if ( ipiece_cap )
+      {
+       switch( ipiece_cap )
+         {
+         case pawn:        CapW( PAWN,       pawn,   pawn );
+                            Xor( to+nfile, BB_WPAWN_ATK );        break;
+         case lance:       CapW( LANCE,      lance,  lance);     break;
+         case knight:      CapW( KNIGHT,     knight, knight);    break;
+         case silver:      CapW( SILVER,     silver, silver);    break;
+         case gold:        CapW( GOLD,       gold,   gold);
+                            Xor( to, BB_WTGOLD );                 break;
+         case bishop:      CapW( BISHOP,     bishop, bishop);
+                           Xor( to, BB_W_BH );                   break;
+         case rook:        CapW( ROOK,       rook,   rook);
+                            Xor( to, BB_W_RD );                   break;
+         case pro_pawn:    CapW( PRO_PAWN,   pawn,   pro_pawn);
+                            Xor( to, BB_WTGOLD );                 break;
+         case pro_lance:   CapW( PRO_LANCE,  lance,  pro_lance);
+                            Xor( to, BB_WTGOLD );                 break;
+         case pro_knight:  CapW( PRO_KNIGHT, knight, pro_knight);
+                            Xor( to, BB_WTGOLD );                 break;
+         case pro_silver:  CapW(PRO_SILVER, silver, pro_silver);
+                            Xor( to, BB_WTGOLD );                 break;
+         case horse:       CapW(HORSE,     bishop, horse);
+                            Xor( to, BB_W_HDK );
+                           Xor( to, BB_W_BH );                   break;
+         default:          assert( ipiece_cap == dragon );
+                            CapW(DRAGON,    rook,   dragon);
+                            Xor( to, BB_W_HDK );
+                            Xor( to, BB_W_RD );                   break;
+         }
+      Xor( to, BB_WOCCUPY );
+      XorFile( from, OCCUPIED_FILE );
+      XorDiag1( from, OCCUPIED_DIAG1 );
+      XorDiag2( from, OCCUPIED_DIAG2 );
+      }
+    else {
+      BOARD[to] = empty;
+      SetClearFile( from, to, OCCUPIED_FILE );
+      SetClearDiag1( from, to, OCCUPIED_DIAG1 );
+      SetClearDiag2( from, to, OCCUPIED_DIAG2 );
+    }
+  }
+
+  assert( exam_bb( ptree ) );
+}
+
+
+void
+unmake_move_w( tree_t * restrict ptree, unsigned int move, int ply )
+{
+  int from = (int)I2From(move);
+  int to   = (int)I2To(move);
+  int nrep = root_nrep + ply - 1;
+
+  HASH_KEY = ptree->rep_board_list[nrep];
+  MATERIAL = ptree->save_material[ply];
+
+  if ( from >= nsquare )
+    {
+      switch( From2Drop(from) )
+       {
+       case pawn:    Xor( to, BB_WPAWN );
+                      Xor( to+nfile, BB_WPAWN_ATK );
+                      HAND_W += flag_hand_pawn;    break;
+       case lance:   Xor( to, BB_WLANCE );
+                      HAND_W += flag_hand_lance;   break;
+       case knight:  Xor( to, BB_WKNIGHT );
+                      HAND_W += flag_hand_knight;  break;
+       case silver:  Xor( to, BB_WSILVER );
+                      HAND_W += flag_hand_silver;  break;
+       case gold:    Xor( to, BB_WGOLD );
+                      Xor( to, BB_WTGOLD );
+                      HAND_W += flag_hand_gold;    break;
+       case bishop:  Xor( to, BB_WBISHOP );
+                      Xor( to, BB_W_BH );
+                      HAND_W += flag_hand_bishop;  break;
+       default:      assert( From2Drop(from) == rook );
+                      Xor( to, BB_WROOK );
+                      Xor( to, BB_W_RD );
+                      HAND_W += flag_hand_rook;    break;
+       }
+
+      BOARD[to] = empty;
+      Xor( to, BB_WOCCUPY );
+      XorFile( to, OCCUPIED_FILE );
+      XorDiag2( to, OCCUPIED_DIAG2 );
+      XorDiag1( to, OCCUPIED_DIAG1 );
+    }
+  else {
+    const int ipiece_move = (int)I2PieceMove(move);
+    const int ipiece_cap  = (int)UToCap(move);
+    const int is_promote  = (int)I2IsPromote(move);
+    bitboard_t bb_set_clear;
+
+    BBOr( bb_set_clear, abb_mask[from], abb_mask[to] );
+    SetClear( BB_WOCCUPY );
+
+    if ( is_promote ) switch( ipiece_move )
+      {
+      case pawn:    NocapPro( WPAWN, WPRO_PAWN, -pawn );
+                    Xor( to, BB_WPAWN_ATK );
+                    Xor( to, BB_WTGOLD );                        break;
+      case lance:   NocapPro( WLANCE, WPRO_LANCE, -lance );
+                    Xor( to, BB_WTGOLD );                        break;
+      case knight:  NocapPro( WKNIGHT, WPRO_KNIGHT, -knight );
+                    Xor( to, BB_WTGOLD );                        break;
+      case silver:  NocapPro( WSILVER, WPRO_SILVER, -silver );
+                    Xor( to, BB_WTGOLD );                        break;
+      case bishop:  NocapPro( WBISHOP, WHORSE, -bishop );
+                    Xor( to, BB_W_HDK );
+                   SetClear( BB_W_BH );                         break;
+      default:      assert( ipiece_move == rook );
+                    NocapPro( WROOK, WDRAGON, -rook );
+                    Xor( to, BB_W_HDK );
+                   SetClear( BB_W_RD );                         break;
+      }
+    else switch ( ipiece_move )
+      {
+      case pawn:        NocapNopro( WPAWN, -pawn );
+                        Xor( to+nfile, BB_WPAWN_ATK );
+                        Xor( to,       BB_WPAWN_ATK );          break;
+      case lance:       NocapNopro( WLANCE,  -lance );          break;
+      case knight:      NocapNopro( WKNIGHT, -knight );         break;
+      case silver:      NocapNopro( WSILVER, -silver );         break;
+      case gold:        NocapNopro( WGOLD,   -gold );
+                        SetClear( BB_WTGOLD );                  break;
+      case bishop:      NocapNopro( WBISHOP, -bishop );
+                        SetClear( BB_W_BH );                    break;
+      case rook:        NocapNopro( WROOK, -rook );
+                        SetClear( BB_W_RD );                    break;
+      case king:       BOARD[from] = -king;
+                        SQ_WKING    = (char)from;
+                        SetClear( BB_W_HDK );                   break;
+      case pro_pawn:    NocapNopro( WPRO_PAWN,  -pro_pawn );
+                        SetClear( BB_WTGOLD );                  break;
+      case pro_lance:   NocapNopro( WPRO_LANCE, -pro_lance );
+                        SetClear( BB_WTGOLD );                  break;
+      case pro_knight:  NocapNopro( WPRO_KNIGHT,-pro_knight );
+                        SetClear( BB_WTGOLD );                  break;
+      case pro_silver:  NocapNopro( WPRO_SILVER, -pro_silver );
+                        SetClear( BB_WTGOLD );                  break;
+      case horse:       NocapNopro( WHORSE, -horse );
+                        SetClear( BB_W_HDK );
+                        SetClear( BB_W_BH );                    break;
+      default:          assert( ipiece_move == dragon );
+                        NocapNopro( WDRAGON, -dragon );
+                        SetClear( BB_W_HDK );
+                        SetClear( BB_W_RD );                    break;
+      }
+    
+    if ( ipiece_cap )
+      {
+       switch( ipiece_cap )
+         {
+         case pawn:        CapB( PAWN,      pawn,   pawn );
+                           Xor( to-nfile, BB_BPAWN_ATK );      break;
+         case lance:       CapB( LANCE,     lance,  lance );   break;
+         case knight:      CapB( KNIGHT,    knight, knight );  break;
+         case silver:      CapB( SILVER,    silver, silver );  break;
+         case gold:        CapB( GOLD,      gold,   gold );
+                            Xor( to, BB_BTGOLD );              break;
+         case bishop:      CapB( BISHOP,    bishop, bishop );
+                            Xor( to, BB_B_BH );                 break;
+         case rook:        CapB( ROOK,      rook,   rook );
+                            Xor( to, BB_B_RD );                 break;
+         case pro_pawn:    CapB( PRO_PAWN,   pawn,   pro_pawn );
+                            Xor( to, BB_BTGOLD );              break;
+         case pro_lance:   CapB( PRO_LANCE,  lance,  pro_lance );
+                            Xor( to, BB_BTGOLD );              break;
+         case pro_knight:  CapB( PRO_KNIGHT, knight, pro_knight );
+                            Xor( to, BB_BTGOLD );              break;
+         case pro_silver:  CapB( PRO_SILVER, silver, pro_silver );
+                            Xor( to, BB_BTGOLD );              break;
+         case horse:       CapB( HORSE,     bishop, horse );
+                            Xor( to, BB_B_HDK );
+                            Xor( to, BB_B_BH );                 break;
+         default:          assert( ipiece_cap == dragon );
+                            CapB( DRAGON,    rook,   dragon);
+                            Xor( to, BB_B_HDK );
+                            Xor( to, BB_B_RD );                 break;
+         }
+       Xor( to, BB_BOCCUPY );
+       XorFile( from, OCCUPIED_FILE );
+       XorDiag1( from, OCCUPIED_DIAG1 );
+       XorDiag2( from, OCCUPIED_DIAG2 );
+      }
+    else {
+      BOARD[to] = empty;
+      SetClearFile( from, to, OCCUPIED_FILE );
+      SetClearDiag1( from, to, OCCUPIED_DIAG1 );
+      SetClearDiag2( from, to, OCCUPIED_DIAG2 );
+    }
+  }
+
+  assert( exam_bb( ptree ) );
+}
+
+
+#undef CapW
+#undef CapB
+#undef NocapNopro
+#undef NocapPro
diff --git a/utility.c b/utility.c
new file mode 100644 (file)
index 0000000..75b1b9a
--- /dev/null
+++ b/utility.c
@@ -0,0 +1,689 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+#include "shogi.h"
+
+
+int
+ini_game( tree_t * restrict ptree, const min_posi_t *pmin_posi, int flag,
+         const char *str_name1, const char *str_name2 )
+{
+  bitboard_t bb;
+  int piece;
+  int sq, iret;
+
+  if ( flag & flag_history )
+    {
+      iret = open_history( str_name1, str_name2 );
+      if ( iret < 0 ) { return iret; }
+    }
+
+  if ( ! ( flag & flag_nofmargin ) )
+    {
+      fmg_misc      = FMG_MISC;
+      fmg_cap       = FMG_CAP;
+      fmg_drop      = FMG_DROP;
+      fmg_mt        = FMG_MT;
+      fmg_misc_king = FMG_MISC_KING;
+      fmg_cap_king  = FMG_CAP_KING;
+    }
+
+  memcpy( ptree->posi.asquare, pmin_posi->asquare, nsquare );
+  ptree->move_last[0]  = ptree->amove;
+  ptree->nsuc_check[0] = 0;
+  ptree->nsuc_check[1] = 0;
+  root_nrep            = 0;
+  root_turn            = pmin_posi->turn_to_move;
+  HAND_B               = pmin_posi->hand_black;
+  HAND_W               = pmin_posi->hand_white;
+  MATERIAL             = 0;
+
+  BBIni( BB_BOCCUPY );
+  BBIni( BB_BPAWN );
+  BBIni( BB_BLANCE );
+  BBIni( BB_BKNIGHT );
+  BBIni( BB_BSILVER );
+  BBIni( BB_BGOLD );
+  BBIni( BB_BBISHOP );
+  BBIni( BB_BROOK );
+  BBIni( BB_BPRO_PAWN );
+  BBIni( BB_BPRO_LANCE );
+  BBIni( BB_BPRO_KNIGHT );
+  BBIni( BB_BPRO_SILVER );
+  BBIni( BB_BHORSE );
+  BBIni( BB_BDRAGON );
+  BBIni( BB_BTGOLD );
+  BBIni( BB_WOCCUPY );
+  BBIni( BB_WPAWN );
+  BBIni( BB_WLANCE );
+  BBIni( BB_WKNIGHT );
+  BBIni( BB_WSILVER );
+  BBIni( BB_WGOLD );
+  BBIni( BB_WBISHOP );
+  BBIni( BB_WROOK );
+  BBIni( BB_WPRO_PAWN );
+  BBIni( BB_WPRO_LANCE );
+  BBIni( BB_WPRO_KNIGHT );
+  BBIni( BB_WPRO_SILVER );
+  BBIni( BB_WHORSE );
+  BBIni( BB_WDRAGON );
+  BBIni( BB_WTGOLD );
+  BBIni( OCCUPIED_FILE );
+  BBIni( OCCUPIED_DIAG1 );
+  BBIni( OCCUPIED_DIAG2 );
+
+  for ( sq = 0; sq < nsquare; sq++ ) {
+    piece = BOARD[sq];
+    if ( piece > 0 ) {
+      Xor( sq, BB_BOCCUPY );
+      XorFile( sq, OCCUPIED_FILE );
+      XorDiag1( sq, OCCUPIED_DIAG1 );
+      XorDiag2( sq, OCCUPIED_DIAG2 );
+      switch ( piece )
+       {
+       case pawn:        Xor( sq, BB_BPAWN );        break;
+       case lance:       Xor( sq, BB_BLANCE );       break;
+       case knight:      Xor( sq, BB_BKNIGHT );      break;
+       case silver:      Xor( sq, BB_BSILVER );      break;
+       case rook:        Xor( sq, BB_BROOK );        break;
+       case bishop:      Xor( sq, BB_BBISHOP );      break;
+       case king:        SQ_BKING = (char)sq;        break;
+       case dragon:      Xor( sq, BB_BDRAGON );      break;
+       case horse:       Xor( sq, BB_BHORSE );       break;
+       case gold:        Xor( sq, BB_BGOLD );        break;
+       case pro_pawn:    Xor( sq, BB_BPRO_PAWN );    break;
+       case pro_lance:   Xor( sq, BB_BPRO_LANCE );   break;
+       case pro_knight:  Xor( sq, BB_BPRO_KNIGHT );  break;
+       case pro_silver:  Xor( sq, BB_BPRO_SILVER );  break;
+       }
+    }
+    else if ( piece < 0 ) {
+      Xor( sq, BB_WOCCUPY );
+      XorFile( sq, OCCUPIED_FILE );
+      XorDiag1( sq, OCCUPIED_DIAG1 );
+      XorDiag2( sq, OCCUPIED_DIAG2 );
+      switch ( - piece )
+       {
+       case pawn:        Xor( sq, BB_WPAWN );        break;
+       case lance:       Xor( sq, BB_WLANCE );       break;
+       case knight:      Xor( sq, BB_WKNIGHT );      break;
+       case silver:      Xor( sq, BB_WSILVER );      break;
+       case rook:        Xor( sq, BB_WROOK );        break;
+       case bishop:      Xor( sq, BB_WBISHOP );      break;
+       case king:        SQ_WKING = (char)sq;        break;
+       case dragon:      Xor( sq, BB_WDRAGON );      break;
+       case horse:       Xor( sq, BB_WHORSE );       break;
+       case gold:        Xor( sq, BB_WGOLD );        break;
+       case pro_pawn:    Xor( sq, BB_WPRO_PAWN );    break;
+       case pro_lance:   Xor( sq, BB_WPRO_LANCE );   break;
+       case pro_knight:  Xor( sq, BB_WPRO_KNIGHT );  break;
+       case pro_silver:  Xor( sq, BB_WPRO_SILVER );  break;
+       }
+    }
+  }
+
+  BBOr( BB_BTGOLD, BB_BPRO_PAWN,   BB_BGOLD );
+  BBOr( BB_BTGOLD, BB_BPRO_LANCE,  BB_BTGOLD );
+  BBOr( BB_BTGOLD, BB_BPRO_KNIGHT, BB_BTGOLD );
+  BBOr( BB_BTGOLD, BB_BPRO_SILVER, BB_BTGOLD );
+  BBOr( BB_B_HDK,  BB_BHORSE,      BB_BDRAGON );
+  BBOr( BB_B_HDK,  BB_BKING,       BB_B_HDK );
+  BBOr( BB_B_BH,   BB_BBISHOP,     BB_BHORSE );
+  BBOr( BB_B_RD,   BB_BROOK,       BB_BDRAGON );
+
+  BBOr( BB_WTGOLD, BB_WPRO_PAWN,   BB_WGOLD );
+  BBOr( BB_WTGOLD, BB_WPRO_LANCE,  BB_WTGOLD );
+  BBOr( BB_WTGOLD, BB_WPRO_KNIGHT, BB_WTGOLD );
+  BBOr( BB_WTGOLD, BB_WPRO_SILVER, BB_WTGOLD );
+  BBOr( BB_W_HDK,  BB_WHORSE,      BB_WDRAGON );
+  BBOr( BB_W_HDK,  BB_WKING,       BB_W_HDK );
+  BBOr( BB_W_BH,   BB_WBISHOP,     BB_WHORSE );
+  BBOr( BB_W_RD,   BB_WROOK,       BB_WDRAGON );
+
+  BB_BPAWN_ATK.p[0]  = ( BB_BPAWN.p[0] <<  9 ) & 0x7ffffffU;
+  BB_BPAWN_ATK.p[0] |= ( BB_BPAWN.p[1] >> 18 ) & 0x00001ffU;
+  BB_BPAWN_ATK.p[1]  = ( BB_BPAWN.p[1] <<  9 ) & 0x7ffffffU;
+  BB_BPAWN_ATK.p[1] |= ( BB_BPAWN.p[2] >> 18 ) & 0x00001ffU;
+  BB_BPAWN_ATK.p[2]  = ( BB_BPAWN.p[2] <<  9 ) & 0x7ffffffU;
+
+  BB_WPAWN_ATK.p[2]  = ( BB_WPAWN.p[2] >>  9 );
+  BB_WPAWN_ATK.p[2] |= ( BB_WPAWN.p[1] << 18 ) & 0x7fc0000U;
+  BB_WPAWN_ATK.p[1]  = ( BB_WPAWN.p[1] >>  9 );
+  BB_WPAWN_ATK.p[1] |= ( BB_WPAWN.p[0] << 18 ) & 0x7fc0000U;
+  BB_WPAWN_ATK.p[0]  = ( BB_WPAWN.p[0] >>  9 );
+
+  MATERIAL = eval_material( ptree );
+  HASH_KEY = hash_func( ptree );
+
+  memset( ptree->hist_good,       0, sizeof(ptree->hist_good) );
+  memset( ptree->hist_tried,      0, sizeof(ptree->hist_tried) );
+  memset( hash_rejections_parent, 0, sizeof(hash_rejections_parent) );
+  memset( hash_rejections,        0, sizeof(hash_rejections) );
+
+  game_status &= ( flag_quiet | flag_reverse | flag_narrow_book
+                  | flag_time_extendable | flag_learning
+                  | flag_nobeep | flag_nostress | flag_nopeek
+                  | flag_noponder | flag_noprompt );
+
+  sec_b_total     = 0;
+  sec_w_total     = 0;
+  sec_elapsed     = 0;
+  last_root_value = 0;
+  n_nobook_move   = 0;
+  last_pv.depth   = 0;
+  last_pv.length  = 0;
+  last_pv.a[0]    = 0;
+  last_pv.a[1]    = 0;
+
+  if ( InCheck( root_turn ) )
+    {
+      ptree->nsuc_check[1] = 1U;
+      if ( is_mate( ptree, 1 ) ) { game_status |= flag_mated; }
+    }
+
+  BBOr( bb, BB_BPAWN, BB_WPAWN );
+  BBOr( bb, bb, BB_BPRO_PAWN );
+  BBOr( bb, bb, BB_WPRO_PAWN );
+  npawn_box  = npawn_max;
+  npawn_box -= PopuCount( bb );
+  npawn_box -= (int)I2HandPawn(HAND_B);
+  npawn_box -= (int)I2HandPawn(HAND_W);
+
+  BBOr( bb, BB_BLANCE, BB_WLANCE );
+  BBOr( bb, bb, BB_BPRO_LANCE );
+  BBOr( bb, bb, BB_WPRO_LANCE );
+  nlance_box  = nlance_max;
+  nlance_box -= PopuCount( bb );
+  nlance_box -= (int)I2HandLance(HAND_B);
+  nlance_box -= (int)I2HandLance(HAND_W);
+  
+  BBOr( bb, BB_BKNIGHT, BB_WKNIGHT );
+  BBOr( bb, bb, BB_BPRO_KNIGHT );
+  BBOr( bb, bb, BB_WPRO_KNIGHT );
+  nknight_box  = nknight_max;
+  nknight_box -= PopuCount( bb );
+  nknight_box -= (int)I2HandKnight(HAND_B);
+  nknight_box -= (int)I2HandKnight(HAND_W);
+
+  BBOr( bb, BB_BSILVER, BB_WSILVER );
+  BBOr( bb, bb, BB_BPRO_SILVER );
+  BBOr( bb, bb, BB_WPRO_SILVER );
+  nsilver_box  = nsilver_max;
+  nsilver_box -= PopuCount( bb );
+  nsilver_box -= (int)I2HandSilver(HAND_B);
+  nsilver_box -= (int)I2HandSilver(HAND_W);
+
+  BBOr( bb, BB_BGOLD, BB_WGOLD );
+  ngold_box  = ngold_max;
+  ngold_box -= PopuCount( bb );
+  ngold_box -= (int)I2HandGold(HAND_B);
+  ngold_box -= (int)I2HandGold(HAND_W);
+
+  BBOr( bb, BB_BBISHOP, BB_WBISHOP );
+  BBOr( bb, bb, BB_BHORSE );
+  BBOr( bb, bb, BB_WHORSE );
+  nbishop_box  = nbishop_max;
+  nbishop_box -= PopuCount( bb );
+  nbishop_box -= (int)I2HandBishop(HAND_B);
+  nbishop_box -= (int)I2HandBishop(HAND_W);
+
+  BBOr( bb, BB_BROOK, BB_WROOK );
+  BBOr( bb, bb, BB_BDRAGON );
+  BBOr( bb, bb, BB_WDRAGON );
+  nrook_box  = nrook_max;
+  nrook_box -= PopuCount( bb );
+  nrook_box -= (int)I2HandRook(HAND_B);
+  nrook_box -= (int)I2HandRook(HAND_W);
+
+  iret = exam_tree( ptree );
+  if ( iret < 0 )
+    {
+      ini_game( ptree, &min_posi_no_handicap, 0, NULL, NULL );
+      return iret;
+    }
+
+  return 1;
+}
+
+
+int
+gen_legal_moves( tree_t * restrict ptree, unsigned int *p0 )
+{
+  unsigned int *p1;
+  int i, j, n;
+
+  p1 = GenCaptures( root_turn, p0 );
+  p1 = GenNoCaptures( root_turn, p1 );
+  p1 = GenCapNoProEx2( root_turn, p1 );
+  p1 = GenNoCapNoProEx2( root_turn, p1 );
+  p1 = GenDrop( root_turn, p1 );
+  n  = (int)( p1 - p0 );
+
+  for ( i = 0; i < n; i++ )
+    {
+      MakeMove( root_turn, p0[i], 1 );
+      if ( InCheck( root_turn ) )
+       {
+         UnMakeMove( root_turn, p0[i], 1 );
+         p0[i] = 0;
+         continue;
+       }
+      if ( InCheck(Flip(root_turn)) )
+       {
+         ptree->nsuc_check[2] = (unsigned char)( ptree->nsuc_check[0] + 1U );
+         if ( ptree->nsuc_check[2] >= 6U
+              && ( detect_repetition( ptree, 2, Flip(root_turn), 3 )
+                   == perpetual_check ) )
+           {
+             UnMakeMove( root_turn, p0[i], 1 );
+             p0[i] = 0;
+             continue;
+           }
+       }
+      UnMakeMove( root_turn, p0[i], 1 );
+    }
+
+  for ( i = 0; i < n; )
+    {
+      if ( ! p0[i] )
+       {
+         for ( j = i+1; j < n; j++ ) { p0[j-1] = p0[j]; }
+         n -= 1;
+       }
+      else { i++; }
+    }
+  
+  return n;
+}
+
+
+/*
+  - detection of perpetual check is omitted.
+  - weak moves are omitted.
+*/
+int
+is_mate( tree_t * restrict ptree, int ply )
+{
+  int iret = 0;
+
+  assert( InCheck(root_turn) );
+
+  ptree->move_last[ply] = GenEvasion( root_turn, ptree->move_last[ply-1] );
+  if ( ptree->move_last[ply] == ptree->move_last[ply-1] ) { iret = 1; }
+
+  return iret;
+}
+
+
+int
+is_hand_eq_supe( unsigned int u, unsigned int uref )
+{
+#if 1
+/* aggressive superior correspondences are applied, that is:
+ *   pawn  <= lance, silver, gold, rook
+ *   lance <= rook.
+ */
+  int nsupe;
+
+  if ( IsHandKnight(u) < IsHandKnight(uref)
+       || IsHandSilver(u) < IsHandSilver(uref)
+       || IsHandGold(u)   < IsHandGold(uref)
+       || IsHandBishop(u) < IsHandBishop(uref)
+       || IsHandRook(u)   < IsHandRook(uref) ) { return 0; }
+
+  nsupe  = (int)I2HandRook(u)  - (int)I2HandRook(uref);
+  nsupe += (int)I2HandLance(u) - (int)I2HandLance(uref);
+  if ( nsupe < 0 ) { return 0; }
+
+  nsupe += (int)I2HandSilver(u) - (int)I2HandSilver(uref);
+  nsupe += (int)I2HandGold(u)   - (int)I2HandGold(uref);
+  nsupe += (int)I2HandPawn(u)   - (int)I2HandPawn(uref);
+  if ( nsupe < 0 ) { return 0; }
+
+  return 1;
+#else
+  if ( IsHandPawn(u) >= IsHandPawn(uref)
+       && IsHandLance(u)  >= IsHandLance(uref)
+       && IsHandKnight(u) >= IsHandKnight(uref)
+       && IsHandSilver(u) >= IsHandSilver(uref)
+       && IsHandGold(u)   >= IsHandGold(uref)
+       && IsHandBishop(u) >= IsHandBishop(uref)
+       && IsHandRook(u)   >= IsHandRook(uref) ) { return 1; }
+  
+  return 0;
+#endif
+}
+
+
+/* weak moves are omitted. */
+int
+detect_repetition( tree_t * restrict ptree, int ply, int turn, int nth )
+{
+  const unsigned int *p;
+  unsigned int hand1, hand2;
+  int n, i, imin, counter, irep, ncheck;
+
+  ncheck = (int)ptree->nsuc_check[ply];
+  n      = root_nrep + ply - 1;
+
+  /*if ( ncheck >= 6 )*/
+  if ( ncheck >= nth * 2 )
+    {
+      /* imin = n - ncheck*2; */
+      imin = n - ncheck*2 + 1;
+      if ( imin < 0 ) { imin = 0; }
+
+      ptree->move_last[ply] = GenEvasion( turn, ptree->move_last[ply-1] );
+      for ( p = ptree->move_last[ply-1]; p < ptree->move_last[ply]; p++ )
+       {
+         MakeMove( turn, *p, ply );
+
+         /* for ( i = n-1, counter = 0; i >= imin; i -= 2 ) */
+         for ( i = n-3, counter = 0; i >= imin; i -= 2 )
+           {
+             if ( ptree->rep_board_list[i] == HASH_KEY
+                  && ptree->rep_hand_list[i] == HAND_B
+                  && ++counter == nth )
+                  /* && ncheck*2 - 1 >= n - i )*/
+               {
+                 UnMakeMove( turn, *p, ply );
+                 move_evasion_pchk = *p;
+                 return perpetual_check;
+               }
+           }
+         UnMakeMove( turn, *p, ply );
+       }
+    }
+
+  irep = no_rep;
+  for ( i = n-4, counter = 0; i >= 0; i-- )
+    {
+      if ( ptree->rep_board_list[i] == HASH_KEY )
+       {
+         hand1 = HAND_B;
+         hand2 = ptree->rep_hand_list[i];
+
+         if ( (n-i) & 1 )
+           {
+             if ( irep == no_rep )
+               {
+                 if ( turn )
+                   {
+                     if ( is_hand_eq_supe( hand2, hand1 ) )
+                       {
+                         irep = white_superi_rep;
+                       }
+                   }
+                 else if ( is_hand_eq_supe( hand1, hand2 ) )
+                   {
+                     irep = black_superi_rep;
+                   }
+               }
+           }
+         else if ( hand1 == hand2 )
+           {
+             if ( ++counter == nth )
+               {
+                 if ( (ncheck-1)*2 >= n - i ) { return perpetual_check; }
+                 else                         { return four_fold_rep; }
+               }
+           }
+         else if ( irep == no_rep )
+           {
+             if ( is_hand_eq_supe( hand1, hand2 ) )
+               {
+                 irep = black_superi_rep;
+               }
+             else if ( is_hand_eq_supe( hand2, hand1 ) )
+               {
+                 irep = white_superi_rep;
+               }
+           }
+       }
+    }
+
+  return irep;
+}
+
+
+int
+com_turn_start( tree_t * restrict ptree, int flag )
+{
+  const char *str_move;
+  unsigned int move, sec_total;
+  int iret, is_resign, value, ply;
+
+  if ( ! ( flag & flag_from_ponder ) )
+    {
+      assert( ! ( game_status & mask_game_end ) );
+      
+      time_start = time_turn_start;
+      
+      game_status |=  flag_thinking;
+      iret         = iterate( ptree, flag );
+      game_status &= ~flag_thinking;
+      if ( iret < 0 ) { return iret; }
+    }
+  if ( game_status & flag_suspend ) { return 1; }
+
+  move     = last_pv.a[1];
+  value    = root_turn ? -last_root_value : last_root_value;
+  str_move = str_CSA_move( move );
+
+  if ( value < -resign_threshold && last_pv.type != pv_fail_high )
+    {
+#if defined(DEKUNOBOU)
+      if ( dek_ngame )
+       {
+         dek_lost += 1;
+         Out( "Bonanza lost against Dekunobou\n" );
+       }
+#endif
+      is_resign = 1;
+    }
+  else {
+    is_resign = 0;
+
+#if defined(DEKUNOBOU)
+    if ( dek_ngame && ! is_resign
+        && value > ( MT_CAP_DRAGON * 3 ) / 2
+        && value > resign_threshold
+        && value != score_inferior )
+      {
+       is_resign = 1;
+       dek_win  += 1;
+       Out( "Bonanza won against Dekunobou.\n" );
+      }
+    if ( dek_ngame && ! is_resign && value == -score_draw )
+      {
+       iret = make_move_root( ptree, move, ( flag_rep | flag_nomake_move ) );
+       if ( iret < 0 )
+         {
+           Out( "%s\n\n", str_move );
+           return iret;
+         }
+       else if ( iret == 2 )
+         {
+           is_resign = 1;
+           Out( "The game with Dekunobou is drawn.\n" );
+         }
+      }
+    if ( dek_ngame && ! is_resign && record_game.moves > 255 )
+      {
+       is_resign = 1;
+       Out( "The game with Dekunobou is interrupted...\n" );
+      }
+#endif
+  }
+
+#if defined(DBG_EASY)
+  if ( easy_move && easy_move != move )
+    {
+      out_warning( "EASY MOVE DITECTION FAILED." );
+    }
+#endif
+
+  /* send urgent outputs */
+  if ( is_resign )
+    {
+#if defined(CSA_LAN)
+      if ( sckt_csa != SCKT_NULL )
+       {
+         iret = sckt_out( sckt_csa, "%%TORYO\n" );
+         if ( iret < 0 ) { return iret; }
+       }
+#endif
+      OutCsaShogi( "resign\n" );
+      OutDek( "%%TORYO\n" );
+    }
+  else {
+#if defined(CSA_LAN)
+    if ( sckt_csa != SCKT_NULL )
+      {
+       iret = sckt_out( sckt_csa, "%c%s\n", ach_turn[root_turn], str_move );
+       if ( iret < 0 ) { return iret; }
+      }
+#endif
+
+    OutCsaShogi( "move%s\n", str_move );
+    OutDek( "%c%s\n", ach_turn[root_turn], str_move );
+  }
+  OutBeep();
+
+  /* learning and stuff */;
+  ply = record_game.moves;
+  if ( ply < HASH_REG_HIST_LEN )
+    {
+      history_book_learn[ply].data             &= ~( (1U<<31) | 0xffffU );
+      history_book_learn[ply].data             |= (unsigned int)(value+32768);
+      history_book_learn[ply].move_responsible  = move;
+      history_book_learn[ply].key_responsible   = (unsigned int)HASH_KEY;
+      history_book_learn[ply].hand_responsible  = (unsigned int)HAND_B;
+    }
+
+  iret = hash_learn( ptree, move, value, iteration_depth - 1 );
+  if ( iret < 0 ) { return iret; }
+
+  /* show search result and make a move */
+  if ( is_resign )
+    {
+      show_prompt();
+      game_status |= flag_resigned;
+      renovate_time( root_turn );
+      out_CSA( ptree, &record_game, MOVE_RESIGN );
+      sec_total = root_turn ? sec_w_total : sec_b_total;
+      str_move  = "resign";
+    }
+  else {
+    show_prompt();
+    iret = make_move_root( ptree, move,
+                          ( flag_rep | flag_time | flag_history
+                            | flag_rejections ) );
+    if ( iret < 0 )
+      {
+       Out( "%s\n\n", str_move );
+       return iret;
+      }
+    sec_total = root_turn ? sec_b_total : sec_w_total;
+  }
+
+  OutCsaShogi( "info tt %03u:%02u\n", sec_total / 60U, sec_total % 60U );
+  Out( "%s '(%d%s) %03u:%02u/%03u:%02u  elapsed: b%u, w%u\n",
+       str_move, value,
+       ( last_pv.type == pv_fail_high ) ? "!" : "",
+       sec_elapsed / 60U, sec_elapsed % 60U,
+       sec_total   / 60U, sec_total   % 60U,
+       sec_b_total, sec_w_total );
+  if ( ! is_resign )
+    {
+#if ! defined(NO_STDOUT)
+      iret = out_board( ptree, stdout, move, 0 );
+      if ( iret < 0 ) { return iret; }
+#endif
+    }
+  
+  return 1;
+}
+
+
+#if defined(MNJ_LAN)
+int mnj_reset_tbl( int sd, unsigned int seed )
+{
+  double average, deviation, d;
+  unsigned int u;
+  int i, j;
+
+  if ( clear_trans_table() < 0 ) { return -1; }
+  ehash_clear();
+
+  if ( sd <= 0 )
+    {
+      for ( i = 0; i < MNJ_MASK + 1; i++ ) { mnj_tbl[i] = 0; }
+      return 1;
+    }
+
+  ini_rand( seed );
+
+  for( i = 0; i < MNJ_MASK + 1; i++ )
+    {
+      d = -6.0;
+
+      for ( j = 0; j < 12; j++ ) { d += (double)rand32() / (double)UINT_MAX; }
+      mnj_tbl[i] = (short)( (double)sd * d );
+    }
+
+  average = 0.0;
+  for ( i = 0; i < MNJ_MASK + 1; i++ ) { average += (double)mnj_tbl[i]; }
+  average /= (double)( MNJ_MASK + 1 );
+
+  deviation = 0.0;
+  for ( i = 0; i < MNJ_MASK + 1; i++ )
+    {
+      d = (double)mnj_tbl[i] - average;
+      deviation += d * d;
+    }
+  deviation = sqrt( deviation / (double)( MNJ_MASK + 1 ) );
+
+  if ( get_elapsed( &u ) < 0 ) { return -1; }
+  ini_rand( u );
+
+  Out( "\nThe normal distribution N(0,sd^2) is generated.\n" );
+  Out( "  actual average:            % .3f\n", average );
+  Out( "  actual standard deviation: % .3f\n", deviation );
+  Out( "rand seed = %x\n", u );
+
+  return 1;
+}
+#endif
+
+
+void *
+memory_alloc( size_t nbytes )
+{
+#if defined(_WIN32)
+  void *p = VirtualAlloc( NULL, nbytes, MEM_COMMIT, PAGE_READWRITE );
+  if ( p == NULL ) { str_error = "VirturlAlloc() faild"; }
+#else
+  void *p = malloc( nbytes );
+  if ( p == NULL ) { str_error = "malloc() faild"; }
+#endif
+  return p;
+}
+
+
+int
+memory_free( void *p )
+{
+#if defined(_WIN32)
+  if ( VirtualFree( p, 0, MEM_RELEASE ) ) { return 1; }
+  str_error = "VirtualFree() faild";
+  return -2;
+#else
+  free( p );
+  return 1;
+#endif
+}
diff --git a/valid.c b/valid.c
new file mode 100644 (file)
index 0000000..e462c62
--- /dev/null
+++ b/valid.c
@@ -0,0 +1,197 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+
+int
+is_move_valid( tree_t * restrict __ptree__, unsigned int move, int turn )
+{
+  tree_t * restrict ptree = __ptree__;
+  int from = (int)I2From(move);
+  int to   = (int)I2To(move);
+  int piece_move;
+  unsigned int u;
+  bitboard_t bb;
+
+  if ( from < nsquare )
+    {
+      piece_move = (int)I2PieceMove(move);
+      if ( turn )
+       {
+         if ( BOARD[from] != -piece_move )       { return 0; }
+         if ( BOARD[to]   != (int)UToCap(move) ) { return 0; }
+       }
+      else {
+       if ( BOARD[from] !=  piece_move )        { return 0; }
+       if ( BOARD[to]   != -(int)UToCap(move) ) { return 0; }
+      }
+      
+      switch ( piece_move )
+       {
+       case 0:  return 0;
+
+       case lance:  case bishop:  case horse:  case rook:  case dragon:
+         BBOr( bb, BB_BOCCUPY, BB_WOCCUPY );
+         BBAnd( bb, bb, abb_obstacle[from][to] );
+         if ( BBToU( bb ) ) { return 0; }
+         break;
+       }
+
+      return 1;
+    }
+
+  if ( BOARD[to] ) { return 0; }
+  else {
+    u = turn ? HAND_W : HAND_B;
+    switch ( From2Drop(from) )
+      {
+      case pawn:
+       if ( ! IsHandPawn(u) ) { return 0; }
+       {
+         if ( turn )
+           {
+             u = BBToU( BB_WPAWN_ATK );
+             if ( ( mask_file1 >> aifile[to] ) & u ) { return 0; }
+             if ( IsMateWPawnDrop(__ptree__, to) )   { return 0; }
+           }
+         else {
+           u = BBToU( BB_BPAWN_ATK );
+           if ( ( mask_file1 >> aifile[to] ) & u ) { return 0; }
+           if ( IsMateBPawnDrop(__ptree__, to) )   { return 0; }
+         }
+         return 1;
+       }
+      case lance:   if ( IsHandLance(u) )  { return 1; }  break;
+      case knight:  if ( IsHandKnight(u) ) { return 1; }  break;
+      case silver:  if ( IsHandSilver(u) ) { return 1; }  break;
+      case gold:    if ( IsHandGold(u) )   { return 1; }  break;
+      case bishop:  if ( IsHandBishop(u) ) { return 1; }  break;
+      default:      assert( From2Drop(from) == rook );
+                    if ( IsHandRook(u) )   { return 1; }  break;
+      }
+  }
+  return 0;
+}
+
+
+#define NpchkReturn(piece) if ( (n ## piece) > (n ## piece ## _max) ) {  \
+                             str_error = "too many " # piece "s";        \
+                             return -2; }
+
+int
+exam_tree( const tree_t * restrict ptree )
+{
+  int npawn, nlance, nknight, nsilver, ngold, nbishop, nrook;
+  int nwking, nbking, isquare, ifile, irank, wcounter, bcounter;
+
+  /* total number of each piece */
+  npawn   = (int)(I2HandPawn( HAND_B )   + I2HandPawn( HAND_W ));
+  nlance  = (int)(I2HandLance( HAND_B )  + I2HandLance( HAND_W ));
+  nknight = (int)(I2HandKnight( HAND_B ) + I2HandKnight( HAND_W ));
+  nsilver = (int)(I2HandSilver( HAND_B ) + I2HandSilver( HAND_W ));
+  ngold   = (int)(I2HandGold( HAND_B )   + I2HandGold( HAND_W ));
+  nbishop = (int)(I2HandBishop( HAND_B ) + I2HandBishop( HAND_W ));
+  nrook   = (int)(I2HandRook( HAND_B )   + I2HandRook( HAND_W ));
+  nwking = nbking = 0;
+
+  for ( isquare = 0; isquare < nsquare; isquare++ )
+    switch ( abs( BOARD[isquare] ) )
+      {
+      case empty:                                 break;
+      case pawn:    case pro_pawn:    npawn++;    break;
+      case lance:   case pro_lance:   nlance++;   break;
+      case knight:  case pro_knight:  nknight++;  break;
+      case silver:  case pro_silver:  nsilver++;  break;
+      case gold:                      ngold++;    break;
+      case bishop:  case horse:       nbishop++;  break;
+      case rook:    case dragon:      nrook++;    break;
+      case king:
+       if ( BOARD[isquare] == king ) { nbking++; }
+       else                            { nwking++; }
+       break;
+      }
+  NpchkReturn( pawn );    NpchkReturn( lance );
+  NpchkReturn( knight );  NpchkReturn( silver );
+  NpchkReturn( gold );    NpchkReturn( bishop );
+  NpchkReturn( rook );
+  if ( nbking != 1 || nwking != 1 )
+    {
+      str_error = "invalid number of kings";
+      return -2;
+    }
+
+  /* double pawns */
+  for ( ifile = 0; ifile < 9; ifile++ )
+    {
+      bcounter = wcounter = 0;
+      for ( irank = 0; irank < 9; irank++ )
+       {
+         if ( BOARD[ irank*nfile+ifile ] ==  pawn ) { bcounter++; }
+         if ( BOARD[ irank*nfile+ifile ] == -pawn ) { wcounter++; }
+       }
+      if ( bcounter > 1 )
+       {
+         str_error = "two black pawns at a file";
+         return -2;
+       }
+      if ( wcounter > 1 )
+       {
+         str_error="two white pawns at a file";
+         return -2;
+       }
+    }
+
+  /* pieces can not move */
+  for ( isquare = 0; isquare < 9; isquare++ )
+    {
+      if ( BOARD[ isquare ] == pawn )
+       {
+         str_error = "black pawns in rank 1";
+         return -2;
+       }
+      if ( BOARD[ isquare ] == lance )
+       {
+         str_error = "black lances in rank 1";
+         return -2;
+       }
+    }
+  for ( isquare = 0; isquare < 18; isquare++ )
+    if ( BOARD[ isquare ] == knight )
+      {
+       str_error = "black knights in rank 1-2";
+       return -2;
+      }
+
+  for ( isquare = 72; isquare < 81; isquare++ )
+    {
+      if ( BOARD[ isquare ] == -pawn )
+       {
+         str_error = "white pawns in rank 9";
+         return -2;
+       }
+      if ( BOARD[ isquare ] == -lance )
+       {
+         str_error = "white lances in rank 9";
+         return -2;
+       }
+    }
+  for ( isquare = 63; isquare < 81; isquare++ )
+    if ( BOARD[ isquare ] == -knight )
+      {
+       str_error = "white knights in rank 8-9";
+       return -2;
+      }
+
+  if ( InCheck( Flip(root_turn) ) )
+    {
+      str_error = str_king_hang;
+      return -2;
+    }
+
+  assert( exam_bb( ptree ) );
+
+  return 1;
+}
+
+#undef NpchkReturn