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) )
+       {
+        &n