--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+"icon" ICON "bonanza.ico"\r
--- /dev/null
+#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 */
--- /dev/null
+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
--- /dev/null
+#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;
+}
--- /dev/null
+#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 } };
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if ! defined(_WIN32)
+# include <unistd.h>
+#endif
+#include "shogi.h"
+
+#if defined(_MSC_VER)
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+#else
+static int first_one00( int pcs );
+static int last_one00( int pcs );
+#endif
+
+
+static void ini_check_table( void );
+static bitboard_t bb_set_mask( int isquare );
+static int load_fv( void );
+static void set_attacks( int irank, int ifilea, bitboard_t *pbb );
+static void ini_is_same( void );
+static void ini_tables( void );
+static void ini_attack_tables( void );
+static void ini_random_table( void );
+
+
+static int
+load_fv( void )
+{
+ FILE *pf;
+ size_t size;
+ int iret;
+
+ pf = file_open( str_fv, "rb" );
+ if ( pf == NULL ) { return -2; }
+
+ size = nsquare * pos_n;
+ if ( fread( pc_on_sq, sizeof(short), size, pf ) != size )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ size = nsquare * nsquare * kkp_end;
+ if ( fread( kkp, sizeof(short), size, pf ) != size )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ iret = file_close( pf );
+ if ( iret < 0 ) { return iret; }
+
+#if 0
+# define X0 -10000
+# define X1 +10000
+ {
+ unsigned int a[X1-X0+1];
+ int i, n, iv;
+
+ for ( i = 0; i < X1-X0+1; i++ ) { a[i] = 0; }
+ n = nsquare * pos_n;
+ for ( i = 0; i < n; i++ )
+ {
+ iv = pc_on_sq[0][i];
+ if ( iv < X0 ) { iv = X0; }
+ else if ( iv > X1 ) { iv = X1; }
+ a[ iv - X0 ] += 1;
+ }
+
+ pf = file_open( "dist.dat", "w" );
+ if ( pf == NULL ) { return -2; }
+
+ for ( i = X0; i <= X1; i++ ) { fprintf( pf, "%d %d\n", i, a[i-X0] ); }
+
+ iret = file_close( pf );
+ if ( iret < 0 ) { return iret; }
+ }
+# undef x0
+# undef x1
+#endif
+
+ return 1;
+}
+
+/*
+static int
+ini_fv( void )
+{
+ FILE *pf;
+ size_t size, i;
+
+ pf = file_open( str_fv, "wb" );
+ if ( pf == NULL ) { return -2; }
+
+ size = nsquare * pos_n;
+ for ( i = 0; i < size; i++ ) { pc_on_sq[0][i] = 0; }
+ if ( fwrite( pc_on_sq, sizeof(short), size, pf ) != size )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ size = nsquare * nsquare * kkp_end;
+ for ( i = 0; i < size; i++ ) { kkp[0][0][i] = 0; }
+ if ( fwrite( kkp, sizeof(short), size, pf ) != size )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ return file_close( pf );
+}
+*/
+
+int
+ini( tree_t * restrict ptree )
+{
+ int i;
+
+ /*if ( ini_fv() < 0 ) { return -1; }*/
+ if ( load_fv() < 0 ) { return -1; }
+
+ for ( i = 0; i < 31; i++ ) { p_value[i] = 0; }
+ for ( i = 0; i < 31; i++ ) { p_value_ex[i] = 0; }
+ for ( i = 0; i < 15; i++ ) { benefit2promo[i] = 0; }
+ p_value[15+pawn] = DPawn;
+ p_value[15+lance] = DLance;
+ p_value[15+knight] = DKnight;
+ p_value[15+silver] = DSilver;
+ p_value[15+gold] = DGold;
+ p_value[15+bishop] = DBishop;
+ p_value[15+rook] = DRook;
+ p_value[15+king] = DKing;
+ p_value[15+pro_pawn] = DProPawn;
+ p_value[15+pro_lance] = DProLance;
+ p_value[15+pro_knight] = DProKnight;
+ p_value[15+pro_silver] = DProSilver;
+ p_value[15+horse] = DHorse;
+ p_value[15+dragon] = DDragon;
+
+ game_status = 0;
+ str_buffer_cmdline[0] = '\0';
+ ptrans_table_orig = NULL;
+ record_game.pf = NULL;
+ node_per_second = TIME_CHECK_MIN_NODE;
+ node_limit = UINT64_MAX;
+ time_response = TIME_RESPONSE;
+ sec_limit = 0;
+ sec_limit_up = 10U;
+ sec_limit_depth = UINT_MAX;
+ depth_limit = PLY_MAX;
+ log2_ntrans_table = 20;
+
+ pf_book = NULL;
+ pf_hash = NULL;
+
+#if defined(TLP)
+ tlp_max = 1;
+ tlp_abort = 0;
+ tlp_num = 0;
+ tlp_idle = 0;
+ tlp_atree_work[0].tlp_id = 0;
+ tlp_atree_work[0].tlp_abort = 0;
+ tlp_atree_work[0].tlp_used = 1;
+ tlp_atree_work[0].tlp_slot = 0;
+ tlp_atree_work[0].tlp_nsibling = 0;
+ if ( lock_init( &tlp_atree_work[0].tlp_lock ) < 0 ) { return -1; }
+ if ( lock_init( &tlp_lock ) < 0 ) { return -1; }
+ for ( i = 0; i < tlp_max; i++ )
+ {
+ tlp_atree_work->tlp_ptrees_sibling[i] = NULL;
+ }
+ for ( i = 1; i < TLP_NUM_WORK; i++ )
+ {
+ tlp_atree_work[i].tlp_slot = (unsigned short)i;
+ tlp_atree_work[i].tlp_used = 0;
+ if ( lock_init( &tlp_atree_work[i].tlp_lock ) < 0 ) { return -1; }
+ }
+# if defined(_WIN32)
+# else
+ if ( pthread_attr_init( &pthread_attr )
+ || pthread_attr_setdetachstate( &pthread_attr,
+ PTHREAD_CREATE_DETACHED ) )
+ {
+ str_error = "pthread_attr_init() failed.";
+ return -1;
+ }
+# endif
+#endif
+
+#if defined(CSA_LAN)
+ sckt_csa = SCKT_NULL;
+ time_last_send = 0U;
+#endif
+
+#if defined(MNJ_LAN)
+ for ( i = 1; i < MNJ_MASK + 1; i++ ) { mnj_tbl[i] = 0; }
+ sckt_mnj = SCKT_NULL;
+ mnj_posi_id = 0;
+ mnj_move_last = 0;
+ time_last_send = 0U;
+#endif
+
+#if defined(_WIN32)
+# if defined(DEKUNOBOU)
+ dek_ngame = 0;
+# endif
+#else
+ clk_tck = (clock_t)sysconf(_SC_CLK_TCK);
+#endif
+
+#if ! defined(NO_LOGGING)
+ pf_log = NULL;
+#endif
+
+#if defined(_MSC_VER)
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+#else
+ for ( i = 0; i < 0x200; i++ )
+ {
+ aifirst_one[i] = (unsigned char)first_one00(i);
+ ailast_one[i] = (unsigned char)last_one00(i);
+ }
+#endif
+
+ for ( i = 0; i < HASH_REG_HIST_LEN; i++ )
+ {
+ history_book_learn[i].move_responsible = 0;
+ history_book_learn[i].move_probed = 0;
+ history_book_learn[i].move_played = 0;
+ }
+
+ ini_rand( 5489U );
+ ini_is_same();
+ ini_tables();
+ ini_attack_tables();
+ ini_random_table();
+ ini_check_table();
+
+ set_derivative_param();
+
+ if ( ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL ) < 0 )
+ {
+ return -1;
+ }
+
+ OutCsaShogi( "%s\n", str_myname );
+ Out( "%s\n", str_myname );
+
+ if ( ini_trans_table() < 0 ) { return -1; }
+
+ if ( book_on() < 0 ) { out_warning( "%s", str_error );}
+ else { Out( "%s found\n", str_book );}
+
+ if ( hash_learn_on() < 0 ) { out_warning( "%s", str_error );}
+ else { Out( "%s found\n", str_hash );}
+
+ if ( get_elapsed( &time_turn_start ) < 0 ) { return -1; }
+
+ ini_rand( time_turn_start );
+ Out( "rand seed = %x\n", time_turn_start );
+
+ resign_threshold = RESIGN_THRESHOLD;
+
+#if defined(MPV)
+ mpv_num = 1;
+ mpv_width = 2 * MT_CAP_PAWN;
+#endif
+
+ return 1;
+}
+
+
+int
+fin( void )
+{
+#if defined(TLP)
+ int i;
+#endif
+
+ memory_free( (void *)ptrans_table_orig );
+
+#if defined(TLP)
+ tlp_abort = 1;
+ while ( tlp_num ) { tlp_yield(); }
+ if ( lock_free( &tlp_atree_work[0].tlp_lock ) < 0 ) { return -1; }
+ if ( lock_free( &tlp_lock ) < 0 ) { return -1; }
+ for ( i = 1; i < TLP_NUM_WORK; i++ )
+ {
+ if ( lock_free( &tlp_atree_work[i].tlp_lock ) < 0 ) { return -1; }
+ }
+# if defined(_WIN32)
+# else
+ if ( pthread_attr_destroy( &pthread_attr ) )
+ {
+ str_error = "pthread_attr_destroy() failed.";
+ return -1;
+ }
+# endif
+#endif
+
+ if ( book_off() < 0 ) { return -1; }
+ if ( record_close( &record_game ) < 0 ) { return -1; }
+#if ! defined(NO_LOGGING)
+ if ( file_close( pf_log ) < 0 ) { return -1; }
+#endif
+
+ return 1;
+}
+
+
+void
+set_derivative_param( void )
+{
+ p_value_ex[15+pawn] = p_value[15+pawn] + p_value[15+pawn];
+ p_value_ex[15+lance] = p_value[15+lance] + p_value[15+lance];
+ p_value_ex[15+knight] = p_value[15+knight] + p_value[15+knight];
+ p_value_ex[15+silver] = p_value[15+silver] + p_value[15+silver];
+ p_value_ex[15+gold] = p_value[15+gold] + p_value[15+gold];
+ p_value_ex[15+bishop] = p_value[15+bishop] + p_value[15+bishop];
+ p_value_ex[15+rook] = p_value[15+rook] + p_value[15+rook];
+ p_value_ex[15+king] = p_value[15+king] + p_value[15+king];
+ p_value_ex[15+pro_pawn] = p_value[15+pro_pawn] + p_value[15+pawn];
+ p_value_ex[15+pro_lance] = p_value[15+pro_lance] + p_value[15+lance];
+ p_value_ex[15+pro_knight] = p_value[15+pro_knight] + p_value[15+knight];
+ p_value_ex[15+pro_silver] = p_value[15+pro_silver] + p_value[15+silver];
+ p_value_ex[15+horse] = p_value[15+horse] + p_value[15+bishop];
+ p_value_ex[15+dragon] = p_value[15+dragon] + p_value[15+rook];
+
+ benefit2promo[7+pawn] = p_value[15+pro_pawn] - p_value[15+pawn];
+ benefit2promo[7+lance] = p_value[15+pro_lance] - p_value[15+lance];
+ benefit2promo[7+knight] = p_value[15+pro_knight] - p_value[15+knight];
+ benefit2promo[7+silver] = p_value[15+pro_silver] - p_value[15+silver];
+ benefit2promo[7+bishop] = p_value[15+horse] - p_value[15+bishop];
+ benefit2promo[7+rook] = p_value[15+dragon] - p_value[15+rook];
+
+ p_value[15-pawn] = p_value[15+pawn];
+ p_value[15-lance] = p_value[15+lance];
+ p_value[15-knight] = p_value[15+knight];
+ p_value[15-silver] = p_value[15+silver];
+ p_value[15-gold] = p_value[15+gold];
+ p_value[15-bishop] = p_value[15+bishop];
+ p_value[15-rook] = p_value[15+rook];
+ p_value[15-king] = p_value[15+king];
+ p_value[15-pro_pawn] = p_value[15+pro_pawn];
+ p_value[15-pro_lance] = p_value[15+pro_lance];
+ p_value[15-pro_knight] = p_value[15+pro_knight];
+ p_value[15-pro_silver] = p_value[15+pro_silver];
+ p_value[15-horse] = p_value[15+horse];
+ p_value[15-dragon] = p_value[15+dragon];
+
+ p_value_ex[15-pawn] = p_value_ex[15+pawn];
+ p_value_ex[15-lance] = p_value_ex[15+lance];
+ p_value_ex[15-knight] = p_value_ex[15+knight];
+ p_value_ex[15-silver] = p_value_ex[15+silver];
+ p_value_ex[15-gold] = p_value_ex[15+gold];
+ p_value_ex[15-bishop] = p_value_ex[15+bishop];
+ p_value_ex[15-rook] = p_value_ex[15+rook];
+ p_value_ex[15-king] = p_value_ex[15+king];
+ p_value_ex[15-pro_pawn] = p_value_ex[15+pro_pawn];
+ p_value_ex[15-pro_lance] = p_value_ex[15+pro_lance];
+ p_value_ex[15-pro_knight] = p_value_ex[15+pro_knight];
+ p_value_ex[15-pro_silver] = p_value_ex[15+pro_silver];
+ p_value_ex[15-horse] = p_value_ex[15+horse];
+ p_value_ex[15-dragon] = p_value_ex[15+dragon];
+
+ benefit2promo[7-pawn] = benefit2promo[7+pawn];
+ benefit2promo[7-lance] = benefit2promo[7+lance];
+ benefit2promo[7-knight] = benefit2promo[7+knight];
+ benefit2promo[7-silver] = benefit2promo[7+silver];
+ benefit2promo[7-bishop] = benefit2promo[7+bishop];
+ benefit2promo[7-rook] = benefit2promo[7+rook];
+}
+
+
+static void
+ini_is_same( void )
+{
+ int p[16], i, j;
+
+ for ( i = 0; i < 16; i++ ) { p[i] = 0; }
+
+ p[pawn] = 1;
+ p[lance] = 3;
+ p[pro_pawn] = 3;
+ p[knight] = 3;
+ p[pro_lance] = 3;
+ p[pro_knight] = 3;
+ p[silver] = 4;
+ p[pro_silver] = 4;
+ p[gold] = 5;
+ p[bishop] = 6;
+ p[horse] = 7;
+ p[rook] = 7;
+ p[dragon] = 8;
+ p[king] = 99;
+
+ for ( i = 0; i < 16; i++ )
+ for ( j = 0; j < 16; j++ )
+ {
+ if ( p[i] < p[j]-1 ) { is_same[i][j] = 2U; }
+ else if ( p[i] > p[j]+1 ) { is_same[i][j] = 1U; }
+ else { is_same[i][j] = 0U; }
+ }
+}
+
+
+static void
+ini_tables( void )
+{
+ const unsigned char aini_rl90[] = { A1, A2, A3, A4, A5, A6, A7, A8, A9,
+ B1, B2, B3, B4, B5, B6, B7, B8, B9,
+ C1, C2, C3, C4, C5, C6, C7, C8, C9,
+ D1, D2, D3, D4, D5, D6, D7, D8, D9,
+ E1, E2, E3, E4, E5, E6, E7, E8, E9,
+ F1, F2, F3, F4, F5, F6, F7, F8, F9,
+ G1, G2, G3, G4, G5, G6, G7, G8, G9,
+ H1, H2, H3, H4, H5, H6, H7, H8, H9,
+ I1, I2, I3, I4, I5, I6, I7, I8, I9 };
+
+ const unsigned char aini_rl45[] = { A9, B1, C2, D3, E4, F5, G6, H7, I8,
+ A8, B9, C1, D2, E3, F4, G5, H6, I7,
+ A7, B8, C9, D1, E2, F3, G4, H5, I6,
+ A6, B7, C8, D9, E1, F2, G3, H4, I5,
+ A5, B6, C7, D8, E9, F1, G2, H3, I4,
+ A4, B5, C6, D7, E8, F9, G1, H2, I3,
+ A3, B4, C5, D6, E7, F8, G9, H1, I2,
+ A2, B3, C4, D5, E6, F7, G8, H9, I1,
+ A1, B2, C3, D4, E5, F6, G7, H8, I9 };
+
+ const unsigned char aini_rr45[] = { I8, I7, I6, I5, I4, I3, I2, I1, I9,
+ H7, H6, H5, H4, H3, H2, H1, H9, H8,
+ G6, G5, G4, G3, G2, G1, G9, G8, G7,
+ F5, F4, F3, F2, F1, F9, F8, F7, F6,
+ E4, E3, E2, E1, E9, E8, E7, E6, E5,
+ D3, D2, D1, D9, D8, D7, D6, D5, D4,
+ C2, C1, C9, C8, C7, C6, C5, C4, C3,
+ B1, B9, B8, B7, B6, B5, B4, B3, B2,
+ A9, A8, A7, A6, A5, A4, A3, A2, A1 };
+ bitboard_t abb_plus1dir[ nsquare ];
+ bitboard_t abb_plus8dir[ nsquare ];
+ bitboard_t abb_plus9dir[ nsquare ];
+ bitboard_t abb_plus10dir[ nsquare ];
+ bitboard_t abb_minus1dir[ nsquare ];
+ bitboard_t abb_minus8dir[ nsquare ];
+ bitboard_t abb_minus9dir[ nsquare ];
+ bitboard_t abb_minus10dir[ nsquare ];
+ bitboard_t bb;
+ int isquare, i, ito, ifrom, irank, ifile;
+ int isquare_rl90, isquare_rl45, isquare_rr45;
+
+ for ( isquare = 0; isquare < nsquare; isquare++ )
+ {
+ isquare_rl90 = aini_rl90[isquare];
+ isquare_rl45 = aini_rl45[isquare];
+ isquare_rr45 = aini_rr45[isquare];
+ abb_mask[isquare] = bb_set_mask( isquare );
+ abb_mask_rl90[isquare] = bb_set_mask( isquare_rl90 );
+ abb_mask_rl45[isquare] = bb_set_mask( isquare_rl45 );
+ abb_mask_rr45[isquare] = bb_set_mask( isquare_rr45 );
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nfile; ifile++ )
+ {
+ isquare = irank*nfile + ifile;
+ BBIni( abb_plus1dir[isquare] );
+ BBIni( abb_plus8dir[isquare] );
+ BBIni( abb_plus9dir[isquare] );
+ BBIni( abb_plus10dir[isquare] );
+ BBIni( abb_minus1dir[isquare] );
+ BBIni( abb_minus8dir[isquare] );
+ BBIni( abb_minus9dir[isquare] );
+ BBIni( abb_minus10dir[isquare] );
+ for ( i = 1; i < nfile; i++ )
+ {
+ set_attacks( irank, ifile+i, abb_plus1dir + isquare );
+ set_attacks( irank+i, ifile-i, abb_plus8dir + isquare );
+ set_attacks( irank+i, ifile, abb_plus9dir + isquare );
+ set_attacks( irank+i, ifile+i, abb_plus10dir + isquare );
+ set_attacks( irank, ifile-i, abb_minus1dir + isquare );
+ set_attacks( irank-i, ifile+i, abb_minus8dir + isquare );
+ set_attacks( irank-i, ifile, abb_minus9dir + isquare );
+ set_attacks( irank-i, ifile-i, abb_minus10dir + isquare );
+ }
+ }
+
+
+ for ( isquare = 0; isquare < nsquare; isquare++ )
+ {
+ BBOr( abb_plus_rays[isquare],
+ abb_plus1dir[isquare], abb_plus8dir[isquare] );
+ BBOr( abb_plus_rays[isquare],
+ abb_plus_rays[isquare], abb_plus9dir[isquare] );
+ BBOr( abb_plus_rays[isquare],
+ abb_plus_rays[isquare], abb_plus10dir[isquare] );
+ BBOr( abb_minus_rays[isquare],
+ abb_minus1dir[isquare], abb_minus8dir[isquare] );
+ BBOr( abb_minus_rays[isquare],
+ abb_minus_rays[isquare], abb_minus9dir[isquare] );
+ BBOr( abb_minus_rays[isquare],
+ abb_minus_rays[isquare], abb_minus10dir[isquare] );
+ }
+
+
+ for ( ifrom = 0; ifrom < nsquare; ifrom++ )
+ {
+ for ( ito = 0; ito < nsquare; ito++ )
+ {
+ adirec[ifrom][ito] = (unsigned char)direc_misc;
+ }
+
+ BBOr( bb, abb_plus1dir[ifrom], abb_minus1dir[ifrom] );
+ while ( BBToU(bb) )
+ {
+ ito = FirstOne( bb );
+ adirec[ifrom][ito] = (unsigned char)direc_rank;
+ Xor( ito, bb );
+ }
+ BBOr( bb, abb_plus8dir[ifrom], abb_minus8dir[ifrom] );
+ while ( BBToU(bb) )
+ {
+ ito = FirstOne( bb );
+ adirec[ifrom][ito] = (unsigned char)direc_diag1;
+ Xor( ito, bb );
+ }
+ BBOr( bb, abb_plus9dir[ifrom], abb_minus9dir[ifrom] );
+ while ( BBToU(bb) )
+ {
+ ito = FirstOne( bb );
+ adirec[ifrom][ito] = (unsigned char)direc_file;
+ Xor(ito,bb);
+ }
+ BBOr( bb, abb_plus10dir[ifrom], abb_minus10dir[ifrom] );
+ while ( BBToU(bb) )
+ {
+ ito = FirstOne( bb );
+ adirec[ifrom][ito] = (unsigned char)direc_diag2;
+ Xor( ito, bb );
+ }
+ }
+
+ for ( ifrom = 0; ifrom < nsquare; ifrom++ )
+ for ( ito = 0; ito < nsquare; ito++ )
+ {
+ BBIni( abb_obstacle[ifrom][ito] );
+
+ if ( ifrom-ito > 0 ) switch ( adirec[ifrom][ito] )
+ {
+ case direc_rank:
+ BBXor( abb_obstacle[ifrom][ito],
+ abb_minus1dir[ito+1], abb_minus1dir[ifrom] );
+ break;
+ case direc_file:
+ BBXor( abb_obstacle[ifrom][ito],
+ abb_minus9dir[ito+9], abb_minus9dir[ifrom] );
+ break;
+ case direc_diag1:
+ BBXor( abb_obstacle[ifrom][ito],
+ abb_minus8dir[ito+8], abb_minus8dir[ifrom] );
+ break;
+ case direc_diag2:
+ BBXor( abb_obstacle[ifrom][ito],
+ abb_minus10dir[ito+10], abb_minus10dir[ifrom] );
+ break;
+ }
+ else switch ( adirec[ifrom][ito] )
+ {
+ case direc_rank:
+ BBXor( abb_obstacle[ifrom][ito],
+ abb_plus1dir[ito-1], abb_plus1dir[ifrom] );
+ break;
+ case direc_file:
+ BBXor( abb_obstacle[ifrom][ito],
+ abb_plus9dir[ito-9], abb_plus9dir[ifrom] );
+ break;
+ case direc_diag1:
+ BBXor( abb_obstacle[ifrom][ito],
+ abb_plus8dir[ito-8], abb_plus8dir[ifrom] );
+ break;
+ case direc_diag2:
+ BBXor( abb_obstacle[ifrom][ito],
+ abb_plus10dir[ito-10], abb_plus10dir[ifrom] );
+ break;
+ }
+ }
+}
+
+
+static void
+ini_random_table( void )
+{
+ int i;
+
+ for ( i = 0; i < nsquare; i++ )
+ {
+ b_pawn_rand[ i ] = rand64();
+ b_lance_rand[ i ] = rand64();
+ b_knight_rand[ i ] = rand64();
+ b_silver_rand[ i ] = rand64();
+ b_gold_rand[ i ] = rand64();
+ b_bishop_rand[ i ] = rand64();
+ b_rook_rand[ i ] = rand64();
+ b_king_rand[ i ] = rand64();
+ b_pro_pawn_rand[ i ] = rand64();
+ b_pro_lance_rand[ i ] = rand64();
+ b_pro_knight_rand[ i ] = rand64();
+ b_pro_silver_rand[ i ] = rand64();
+ b_horse_rand[ i ] = rand64();
+ b_dragon_rand[ i ] = rand64();
+ w_pawn_rand[ i ] = rand64();
+ w_lance_rand[ i ] = rand64();
+ w_knight_rand[ i ] = rand64();
+ w_silver_rand[ i ] = rand64();
+ w_gold_rand[ i ] = rand64();
+ w_bishop_rand[ i ] = rand64();
+ w_rook_rand[ i ] = rand64();
+ w_king_rand[ i ] = rand64();
+ w_pro_pawn_rand[ i ] = rand64();
+ w_pro_lance_rand[ i ] = rand64();
+ w_pro_knight_rand[ i ] = rand64();
+ w_pro_silver_rand[ i ] = rand64();
+ w_horse_rand[ i ] = rand64();
+ w_dragon_rand[ i ] = rand64();
+ }
+
+ for ( i = 0; i < npawn_max; i++ )
+ {
+ b_hand_pawn_rand[ i ] = rand64();
+ w_hand_pawn_rand[ i ] = rand64();
+ }
+
+ for ( i = 0; i < nlance_max; i++ )
+ {
+ b_hand_lance_rand[ i ] = rand64();
+ b_hand_knight_rand[ i ] = rand64();
+ b_hand_silver_rand[ i ] = rand64();
+ b_hand_gold_rand[ i ] = rand64();
+ w_hand_lance_rand[ i ] = rand64();
+ w_hand_knight_rand[ i ] = rand64();
+ w_hand_silver_rand[ i ] = rand64();
+ w_hand_gold_rand[ i ] = rand64();
+ }
+
+ for ( i = 0; i < nbishop_max; i++ )
+ {
+ b_hand_bishop_rand[ i ] = rand64();
+ b_hand_rook_rand[ i ] = rand64();
+ w_hand_bishop_rand[ i ] = rand64();
+ w_hand_rook_rand[ i ] = rand64();
+ }
+}
+
+
+static void
+ini_attack_tables( void )
+{
+ int irank, ifile, pcs, i;
+ bitboard_t bb;
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nfile; ifile++ )
+ {
+ BBIni(bb);
+ set_attacks( irank-1, ifile-1, &bb );
+ set_attacks( irank-1, ifile+1, &bb );
+ set_attacks( irank+1, ifile-1, &bb );
+ set_attacks( irank+1, ifile+1, &bb );
+ set_attacks( irank-1, ifile, &bb );
+ abb_b_silver_attacks[ irank*nfile + ifile ] = bb;
+
+ BBIni(bb);
+ set_attacks( irank-1, ifile-1, &bb );
+ set_attacks( irank-1, ifile+1, &bb );
+ set_attacks( irank+1, ifile-1, &bb );
+ set_attacks( irank+1, ifile+1, &bb );
+ set_attacks( irank+1, ifile, &bb );
+ abb_w_silver_attacks[ irank*nfile + ifile ] = bb;
+
+ BBIni(bb);
+ set_attacks( irank-1, ifile-1, &bb );
+ set_attacks( irank-1, ifile+1, &bb );
+ set_attacks( irank-1, ifile, &bb );
+ set_attacks( irank+1, ifile, &bb );
+ set_attacks( irank, ifile-1, &bb );
+ set_attacks( irank, ifile+1, &bb );
+ abb_b_gold_attacks[ irank*nfile + ifile ] = bb;
+
+ BBIni(bb);
+ set_attacks( irank+1, ifile-1, &bb );
+ set_attacks( irank+1, ifile+1, &bb );
+ set_attacks( irank+1, ifile, &bb );
+ set_attacks( irank-1, ifile, &bb );
+ set_attacks( irank, ifile-1, &bb );
+ set_attacks( irank, ifile+1, &bb );
+ abb_w_gold_attacks[ irank*nfile + ifile ] = bb;
+
+ BBIni(bb);
+ set_attacks( irank+1, ifile-1, &bb );
+ set_attacks( irank+1, ifile+1, &bb );
+ set_attacks( irank+1, ifile, &bb );
+ set_attacks( irank-1, ifile-1, &bb );
+ set_attacks( irank-1, ifile+1, &bb );
+ set_attacks( irank-1, ifile, &bb );
+ set_attacks( irank, ifile-1, &bb );
+ set_attacks( irank, ifile+1, &bb );
+ abb_king_attacks[ irank*nfile + ifile ] = bb;
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nfile; ifile++ )
+ {
+ BBIni(bb);
+ set_attacks( irank-2, ifile-1, &bb );
+ set_attacks( irank-2, ifile+1, &bb );
+ abb_b_knight_attacks[ irank*nfile + ifile ] = bb;
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nfile; ifile++ )
+ {
+ BBIni(bb);
+ set_attacks( irank+2, ifile-1, &bb );
+ set_attacks( irank+2, ifile+1, &bb );
+ abb_w_knight_attacks[ irank*nfile + ifile ] = bb;
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nrank; ifile++ )
+ for ( pcs = 0; pcs < 128; pcs++ )
+ {
+ BBIni(bb);
+ for ( i = -1; irank+i >= 0; i-- )
+ {
+ set_attacks( irank+i, ifile, &bb );
+ if ( (pcs<<1) & (1 << (8-irank-i)) ) { break; }
+ }
+ for ( i = 1; irank+i <= 8; i++ )
+ {
+ set_attacks( irank+i, ifile, &bb );
+ if ( (pcs<<1) & (1 << (8-irank-i)) ) { break; }
+ }
+ abb_file_attacks[irank*nfile+ifile][pcs] = bb;
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nrank; ifile++ )
+ for ( pcs = 0; pcs < 128; pcs++ )
+ {
+ BBIni(bb);
+ for ( i = -1; ifile+i >= 0; i-- )
+ {
+ set_attacks( irank, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+ }
+ for ( i = 1; ifile+i <= 8; i++ )
+ {
+ set_attacks( irank, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+ }
+ ai_rook_attacks_r0[irank*nfile+ifile][pcs] = bb.p[irank/3];
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nrank; ifile++ )
+ for ( pcs = 0; pcs < 128; pcs++ )
+ {
+ BBIni(bb);
+ if ( ifile <= irank )
+ {
+ for ( i = -1; ifile+i >= 0; i-- )
+ {
+ set_attacks( irank+i, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+ }
+ for ( i = 1; irank+i <= 8; i++ )
+ {
+ set_attacks( irank+i, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+ }
+ }
+ else {
+ for ( i = -1; irank+i >= 0; i-- )
+ {
+ set_attacks( irank+i, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+ }
+ for ( i = 1; ifile+i <= 8; i++ )
+ {
+ set_attacks( irank+i, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (8-ifile-i)) ) { break; }
+ }
+ }
+ abb_bishop_attacks_rl45[irank*nfile+ifile][pcs] = bb;
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nrank; ifile++ )
+ for ( pcs = 0; pcs < 128; pcs++ )
+ {
+ BBIni(bb);
+ if ( ifile+irank >= 8 )
+ {
+ for ( i = -1; irank-i <= 8; i-- )
+ {
+ set_attacks( irank-i, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (irank-i)) ) { break; }
+ }
+ for ( i = 1; ifile+i <= 8; i++ )
+ {
+ set_attacks( irank-i, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (irank-i)) ) { break; }
+ }
+ }
+ else {
+ for ( i = -1; ifile+i >= 0; i-- )
+ {
+ set_attacks( irank-i, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (irank-i)) ) { break; }
+ }
+ for ( i = 1; irank-i >= 0; i++ )
+ {
+ set_attacks( irank-i, ifile+i, &bb );
+ if ( (pcs<<1) & (1 << (irank-i)) ) { break; }
+ }
+ }
+ abb_bishop_attacks_rr45[irank*nfile+ifile][pcs] = bb;
+ }
+
+ for ( i = 0; i < nsquare; i++ )
+ {
+ aslide[i].ir0 = (unsigned char)(i/27);
+ aslide[i].sr0 = (unsigned char)((2-(i/9)%3)*9+1);
+ aslide[i].irl90 = (unsigned char)(2-(i%9)/3);
+ aslide[i].srl90 = (unsigned char)(((i%9)%3)*9+1);
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nfile; ifile++ )
+ {
+ if ( irank >= ifile )
+ {
+ aslide[ irank*nfile+ifile ].irl45
+ = (unsigned char)((irank-ifile)/3);
+ aslide[ irank*nfile+ifile ].srl45
+ = (unsigned char)((2-((irank-ifile)%3))*9+1);
+ }
+ else {
+ aslide[ irank*nfile+ifile ].irl45
+ = (unsigned char)((9+irank-ifile)/3);
+ aslide[ irank*nfile+ifile ].srl45
+ = (unsigned char)((2-((9+irank-ifile)%3))*9+1);
+ }
+ }
+
+ for ( irank = 0; irank < nrank; irank++ )
+ for ( ifile = 0; ifile < nfile; ifile++ )
+ {
+ if ( ifile+irank >= 8 )
+ {
+ aslide[ irank*nfile+ifile ].irr45
+ = (unsigned char)((irank+ifile-8)/3);
+ aslide[ irank*nfile+ifile ].srr45
+ = (unsigned char)((2-((irank+ifile-8)%3))*9+1);
+ }
+ else {
+ aslide[ irank*nfile+ifile ].irr45
+ = (unsigned char)((irank+ifile+1)/3);
+ aslide[ irank*nfile+ifile ].srr45
+ = (unsigned char)((2-((irank+ifile+1)%3))*9+1);
+ }
+ }
+}
+
+
+static void
+set_attacks( int irank, int ifile, bitboard_t *pbb )
+{
+ if ( irank >= rank1 && irank <= rank9 && ifile >= file1 && ifile <= file9 )
+ {
+ Xor( irank*nfile + ifile, *pbb );
+ }
+}
+
+
+static bitboard_t
+bb_set_mask( int isquare )
+{
+ bitboard_t bb;
+
+ if ( isquare > 53 )
+ {
+ bb.p[0] = bb.p[1] = 0;
+ bb.p[2] = 1U << (80-isquare);
+ }
+ else if ( isquare > 26 )
+ {
+ bb.p[0] = bb.p[2] = 0;
+ bb.p[1] = 1U << (53-isquare);
+ }
+ else {
+ bb.p[1] = bb.p[2] = 0;
+ bb.p[0] = 1U << (26-isquare);
+ }
+
+ return bb;
+}
+
+
+static void
+ini_check_table( void )
+{
+ bitboard_t bb_check, bb;
+ int iking, icheck;
+
+ for ( iking = 0; iking < nsquare; iking++ )
+ {
+ /* black gold */
+ BBIni( b_chk_tbl[iking].gold );
+ bb_check = abb_w_gold_attacks[iking];
+ while ( BBToU(bb_check) )
+ {
+ icheck = LastOne( bb_check );
+ BBOr( b_chk_tbl[iking].gold, b_chk_tbl[iking].gold,
+ abb_w_gold_attacks[icheck] );
+ Xor( icheck, bb_check );
+ }
+ BBOr( bb, abb_mask[iking], abb_w_gold_attacks[iking] );
+ BBNot( bb, bb );
+ BBAnd( b_chk_tbl[iking].gold, b_chk_tbl[iking].gold, bb );
+
+ /* black silver */
+ BBIni( b_chk_tbl[iking].silver );
+ bb_check = abb_w_silver_attacks[iking];
+ while ( BBToU(bb_check) )
+ {
+ icheck = LastOne( bb_check );
+ BBOr( b_chk_tbl[iking].silver, b_chk_tbl[iking].silver,
+ abb_w_silver_attacks[icheck] );
+ Xor( icheck, bb_check );
+ }
+ bb_check.p[0] = abb_w_gold_attacks[iking].p[0];
+ while ( bb_check.p[0] )
+ {
+ icheck = last_one0( bb_check.p[0] );
+ BBOr( b_chk_tbl[iking].silver, b_chk_tbl[iking].silver,
+ abb_w_silver_attacks[icheck] );
+ bb_check.p[0] ^= abb_mask[icheck].p[0];
+ }
+ bb_check.p[1] = abb_w_gold_attacks[iking].p[1];
+ while ( bb_check.p[1] )
+ {
+ icheck = last_one1( bb_check.p[1] );
+ b_chk_tbl[iking].silver.p[0]
+ |= abb_w_silver_attacks[icheck].p[0];
+ bb_check.p[1] ^= abb_mask[icheck].p[1];
+ }
+ BBOr( bb, abb_mask[iking], abb_w_silver_attacks[iking] );
+ BBNot( bb, bb );
+ BBAnd( b_chk_tbl[iking].silver, b_chk_tbl[iking].silver, bb );
+
+ /* black knight */
+ BBIni( b_chk_tbl[iking].knight );
+ bb_check = abb_w_knight_attacks[iking];
+ while ( BBToU(bb_check) )
+ {
+ icheck = LastOne( bb_check );
+ BBOr( b_chk_tbl[iking].knight, b_chk_tbl[iking].knight,
+ abb_w_knight_attacks[icheck] );
+ Xor( icheck, bb_check );
+ }
+ bb_check.p[0] = abb_w_gold_attacks[iking].p[0];
+ while ( bb_check.p[0] )
+ {
+ icheck = last_one0( bb_check.p[0] );
+ BBOr( b_chk_tbl[iking].knight, b_chk_tbl[iking].knight,
+ abb_w_knight_attacks[icheck] );
+ bb_check.p[0] ^= abb_mask[icheck].p[0];
+ }
+
+ /* black lance */
+ if ( iking <= I3 ) {
+ BBAnd( b_chk_tbl[iking].lance, abb_plus_rays[iking+nfile],
+ abb_file_attacks[iking][0] );
+ if ( iking <= I7 && iking != A9 && iking != A8 && iking != A7 ) {
+ BBAnd( bb, abb_plus_rays[iking-1], abb_file_attacks[iking-1][0] );
+ BBOr( b_chk_tbl[iking].lance, b_chk_tbl[iking].lance, bb );
+ }
+ if ( iking <= I7 && iking != I9 && iking != I8 && iking != I7 ) {
+ BBAnd( bb, abb_plus_rays[iking+1], abb_file_attacks[iking+1][0] );
+ BBOr( b_chk_tbl[iking].lance, b_chk_tbl[iking].lance, bb );
+ }
+ } else { BBIni( b_chk_tbl[iking].lance ); }
+
+ /* white gold */
+ BBIni( w_chk_tbl[iking].gold );
+ bb_check = abb_b_gold_attacks[iking];
+ while ( BBToU(bb_check) )
+ {
+ icheck = LastOne( bb_check );
+ BBOr( w_chk_tbl[iking].gold, w_chk_tbl[iking].gold,
+ abb_b_gold_attacks[icheck] );
+ Xor( icheck, bb_check );
+ }
+ BBOr( bb, abb_mask[iking], abb_b_gold_attacks[iking] );
+ BBNot( bb, bb );
+ BBAnd( w_chk_tbl[iking].gold, w_chk_tbl[iking].gold, bb );
+
+ /* white silver */
+ BBIni( w_chk_tbl[iking].silver );
+ bb_check = abb_b_silver_attacks[iking];
+ while ( BBToU(bb_check) )
+ {
+ icheck = LastOne( bb_check );
+ BBOr( w_chk_tbl[iking].silver, w_chk_tbl[iking].silver,
+ abb_b_silver_attacks[icheck] );
+ Xor( icheck, bb_check );
+ }
+ bb_check.p[2] = abb_b_gold_attacks[iking].p[2];
+ while ( bb_check.p[2] )
+ {
+ icheck = first_one2( bb_check.p[2] );
+ BBOr( w_chk_tbl[iking].silver, w_chk_tbl[iking].silver,
+ abb_b_silver_attacks[icheck] );
+ bb_check.p[2] ^= abb_mask[icheck].p[2];
+ }
+ bb_check.p[1] = abb_b_gold_attacks[iking].p[1];
+ while ( bb_check.p[1] )
+ {
+ icheck = first_one1( bb_check.p[1] );
+ w_chk_tbl[iking].silver.p[2]
+ |= abb_b_silver_attacks[icheck].p[2];
+ bb_check.p[1] ^= abb_mask[icheck].p[1];
+ }
+ BBOr( bb, abb_mask[iking], abb_b_silver_attacks[iking] );
+ BBNot( bb, bb );
+ BBAnd( w_chk_tbl[iking].silver, w_chk_tbl[iking].silver, bb );
+
+ /* white knight */
+ BBIni( w_chk_tbl[iking].knight );
+ bb_check = abb_b_knight_attacks[iking];
+ while ( BBToU(bb_check) )
+ {
+ icheck = LastOne( bb_check );
+ BBOr( w_chk_tbl[iking].knight, w_chk_tbl[iking].knight,
+ abb_b_knight_attacks[icheck] );
+ Xor( icheck, bb_check );
+ }
+ bb_check.p[2] = abb_b_gold_attacks[iking].p[2];
+ while ( bb_check.p[2] )
+ {
+ icheck = first_one2( bb_check.p[2] );
+ BBOr( w_chk_tbl[iking].knight, w_chk_tbl[iking].knight,
+ abb_b_knight_attacks[icheck] );
+ bb_check.p[2] ^= abb_mask[icheck].p[2];
+ }
+
+ /* white lance */
+ if ( iking >= A7 ) {
+ BBAnd( w_chk_tbl[iking].lance, abb_minus_rays[iking-nfile],
+ abb_file_attacks[iking][0] );
+ if ( iking >= A3 && iking != A3 && iking != A2 && iking != A1 ) {
+ BBAnd( bb, abb_minus_rays[iking-1], abb_file_attacks[iking-1][0] );
+ BBOr( w_chk_tbl[iking].lance, w_chk_tbl[iking].lance, bb );
+ }
+ if ( iking >= A3 && iking != I3 && iking != I2 && iking != I1 ) {
+ BBAnd( bb, abb_minus_rays[iking+1], abb_file_attacks[iking+1][0] );
+ BBOr( w_chk_tbl[iking].lance, w_chk_tbl[iking].lance, bb );
+ }
+ } else { BBIni( w_chk_tbl[iking].lance ); }
+ }
+}
+
+
+#if defined(_MSC_VER)
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+#else
+static int
+first_one00( int pcs )
+{
+ int i;
+
+ for ( i = 0; i < 9; i++ ) { if ( pcs & (1<<(8-i)) ) { break; } }
+ return i;
+}
+
+
+static int
+last_one00( int pcs )
+{
+ int i;
+
+ for ( i = 8; i >= 0; i-- ) { if ( pcs & (1<<(8-i)) ) { break; } }
+ return i;
+}
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#if defined(_WIN32)
+# include <io.h>
+# include <conio.h>
+#else
+# include <sys/time.h>
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+#include "shogi.h"
+
+#if defined(_MSC_VER)
+# include <Share.h>
+# define fopen( file, mode ) _fsopen( file, mode, _SH_DENYNO )
+#endif
+
+#if defined(NO_STDOUT) || defined(WIN32_PIPE)
+static int out_board0( FILE *pf, int piece, int i, int ito, int ifrom );
+# define OutBoard0(a,b,c,d,e,f) out_board0(a,b,c,d,e)
+#else
+static int out_board0( FILE *pf, int piece, int i, int ito, int ifrom,
+ int is_promote );
+# define OutBoard0(a,b,c,d,e,f) out_board0(a,b,c,d,e,f)
+#endif
+
+static int check_input_buffer( void );
+static int read_command( char **pstr_line_end );
+static void out_hand( FILE *pf, unsigned int hand, const char *str_prefix );
+static void out_hand0( FILE *pf, int n, const char *str_prefix,
+ const char *str );
+
+#if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
+void
+out( const char *format, ... )
+{
+ va_list arg;
+ if ( game_status & flag_quiet ) { return; }
+
+# if ! defined(NO_STDOUT)
+ va_start( arg, format );
+ vprintf( format, arg );
+ va_end( arg );
+ fflush( stdout );
+# endif
+
+# if ! defined(NO_LOGGING)
+ if ( ( strchr( format, '\n' ) != NULL || strchr( format, '\r' ) == NULL )
+ && pf_log != NULL )
+ {
+ va_start( arg, format );
+ vfprintf( pf_log, format, arg );
+ va_end( arg );
+ fflush( pf_log );
+ }
+# endif
+}
+#endif
+
+
+#if defined(CSASHOGI)
+void
+out_csashogi( const char *format, ... )
+{
+ va_list arg;
+
+ va_start( arg, format );
+ vprintf( format, arg );
+ va_end( arg );
+
+ fflush( stdout );
+}
+#endif
+
+
+void
+out_file( FILE *pf, const char *format, ... )
+{
+ va_list arg;
+
+ if ( pf != NULL )
+ {
+ va_start( arg, format );
+ vfprintf( pf, format, arg );
+ va_end( arg );
+ fflush( pf );
+ }
+
+#if ! defined(NO_LOGGING)
+ if ( pf_log != NULL )
+ {
+ va_start( arg, format );
+ vfprintf( pf_log, format, arg );
+ va_end( arg );
+ fflush( pf_log );
+ }
+#endif
+
+}
+
+
+void
+out_warning( const char *format, ... )
+{
+ va_list arg;
+
+ fprintf( stderr, "\n%s", str_warning );
+ va_start( arg, format );
+ vfprintf( stderr, format, arg );
+ va_end( arg );
+ fprintf( stderr, "\n\n" );
+ fflush( stderr );
+
+#if ! defined(NO_LOGGING)
+ if ( pf_log != NULL )
+ {
+ fprintf( pf_log, "\n%s", str_warning );
+ va_start( arg, format );
+ vfprintf( pf_log, format, arg );
+ va_end( arg );
+ fprintf( pf_log, "\n\n" );
+ fflush( pf_log );
+ }
+#endif
+
+}
+
+
+void
+out_error( const char *format, ... )
+{
+ va_list arg;
+
+ fprintf( stderr, "\nERROR: " );
+ va_start( arg, format );
+ vfprintf( stderr, format, arg );
+ va_end( arg );
+ fprintf( stderr, "\n\n" );
+ fflush( stderr );
+
+#if ! defined(NO_LOGGING)
+ if ( pf_log != NULL )
+ {
+ fprintf( pf_log, "\nERROR: " );
+ va_start( arg, format );
+ vfprintf( pf_log, format, arg );
+ va_end( arg );
+ fprintf( pf_log, "\n\n" );
+ fflush( pf_log );
+ }
+#endif
+
+}
+
+
+FILE *
+file_open( const char *str_file, const char *str_mode )
+{
+ FILE *pf;
+
+ pf = fopen( str_file, str_mode );
+ if ( pf == NULL )
+ {
+ snprintf( str_message, SIZE_MESSAGE,
+ "%s, %s", str_fopen_error, str_file );
+ str_error = str_message;
+ return NULL;
+ }
+
+ return pf;
+}
+
+
+int
+file_close( FILE *pf )
+{
+ if ( pf == NULL ) { return 1; }
+ if ( ferror( pf ) )
+ {
+ fclose( pf );
+ str_error = str_io_error;
+ return -2;
+ }
+ if ( fclose( pf ) )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ return 1;
+}
+
+
+void
+show_prompt( void )
+{
+ if ( game_status & flag_noprompt ) { return; }
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame )
+ {
+ Out( "Won=%3d Lost=%3d Total=%4d/", dek_win, dek_lost, dek_ngame-1 );
+ }
+#endif
+
+ if ( game_status & flag_drawn ) { Out( "Drawn> " ); }
+ else if ( game_status & flag_mated )
+ {
+ if ( root_turn ) { Out( "Black Mated> " ); }
+ else { Out( "White Mated> " ); }
+ }
+ else if ( game_status & flag_resigned )
+ {
+ if ( root_turn ) { Out( "White Resigned> " ); }
+ else { Out( "Black Resigned> " ); }
+ }
+ else if ( game_status & flag_suspend )
+ {
+ if ( root_turn ) { Out( "White Suspend> " ); }
+ else { Out( "Black Suspend> " ); }
+ }
+ else if ( root_turn ) { Out( "White %d> ", record_game.moves+1 ); }
+ else { Out( "Black %d> ", record_game.moves+1 ); }
+}
+
+
+int
+open_history( const char *str_name1, const char *str_name2 )
+{
+#if defined(NO_LOGGING)
+ char str_file[SIZE_FILENAME];
+ int iret;
+
+ iret = record_close( &record_game );
+ if ( iret < 0 ) { return -1; }
+
+ strncpy( str_file, "game.csa", SIZE_FILENAME-1 );
+ iret = record_open( &record_game, str_file, mode_read_write,
+ str_name1, str_name2 );
+ if ( iret < 0 ) { return -1; }
+
+ return 1;
+#else
+ FILE *pf;
+ int i, iret;
+ char str_file[SIZE_FILENAME];
+
+ if ( record_game.pf != NULL && ! record_game.moves )
+ {
+ record_game.str_name1[0] = '\0';
+ record_game.str_name2[0] = '\0';
+
+ if ( str_name1 )
+ {
+ strncpy( record_game.str_name1, str_name1, SIZE_PLAYERNAME-1 );
+ record_game.str_name1[SIZE_PLAYERNAME-1] = '\0';
+ }
+
+ if ( str_name2 )
+ {
+ strncpy( record_game.str_name2, str_name2, SIZE_PLAYERNAME-1 );
+ record_game.str_name2[SIZE_PLAYERNAME-1] = '\0';
+ }
+ return 1;
+ }
+
+ iret = file_close( pf_log );
+ if ( iret < 0 ) { return -1; }
+
+ iret = record_close( &record_game );
+ if ( iret < 0 ) { return -1; }
+
+ for ( i = 0; i < 999; i++ )
+ {
+ snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
+ str_dir_logs, i );
+ pf = file_open( str_file, "r" );
+ if ( pf == NULL ) { break; }
+ iret = file_close( pf );
+ if ( iret < 0 ) { return -1; }
+ }
+ irecord_game = i;
+
+ snprintf( str_file, SIZE_FILENAME, "%s/n%03d.log",
+ str_dir_logs, i );
+ pf_log = file_open( str_file, "w" );
+ if ( pf_log == NULL ) { return -1; }
+
+ snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
+ str_dir_logs, i );
+ iret = record_open( &record_game, str_file, mode_read_write,
+ str_name1, str_name2 );
+ if ( iret < 0 ) { return -1; }
+
+ return 1;
+#endif
+}
+
+
+int
+out_board( const tree_t * restrict ptree, FILE *pf, unsigned int move,
+ int is_strict )
+{
+ int irank, ifile, i, iret, ito, ifrom;
+
+#if ! defined(WIN32_PIPE)
+ int is_promote;
+#endif
+
+ if ( ! is_strict && move )
+ {
+ ito = I2To( move );
+ ifrom = I2From( move );
+#if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
+ is_promote = I2IsPromote( move );
+#endif
+ }
+ else {
+ ito = ifrom = nsquare;
+#if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
+ is_promote = 0;
+#endif
+ }
+
+ if ( ( game_status & flag_reverse ) && ! is_strict )
+ {
+ fprintf( pf, " <reversed> \n" );
+ fprintf( pf, "' 1 2 3 4 5 6 7 8 9\n" );
+
+ for ( irank = rank9; irank >= rank1; irank-- )
+ {
+ fprintf( pf, "P%d", irank + 1 );
+
+ for ( ifile = file9; ifile >= file1; ifile-- )
+ {
+ i = irank * nfile + ifile;
+ iret = OutBoard0( pf, BOARD[i], i, ito, ifrom, is_promote );
+ if ( iret < 0 ) { return iret; }
+ }
+ fprintf( pf, "\n" );
+ }
+ }
+ else {
+ fprintf( pf, "' 9 8 7 6 5 4 3 2 1\n" );
+
+ for ( irank = rank1; irank <= rank9; irank++ )
+ {
+ fprintf( pf, "P%d", irank + 1 );
+
+ for ( ifile = file1; ifile <= file9; ifile++ )
+ {
+ i = irank * nfile + ifile;
+ iret = OutBoard0( pf, BOARD[i], i, ito, ifrom, is_promote );
+ if ( iret < 0 ) { return iret; }
+ }
+ fprintf( pf, "\n" );
+ }
+ }
+
+ out_hand( pf, HAND_B, "P+" );
+ out_hand( pf, HAND_W, "P-" );
+ fflush( pf );
+
+ return 1;
+}
+
+
+int
+next_cmdline( int is_wait )
+{
+ char *str_line_end;
+ size_t size;
+ int iret;
+
+ str_line_end = strchr( str_buffer_cmdline, '\n' );
+
+ if ( ! str_line_end )
+ {
+ if ( is_wait )
+ {
+ do {
+ iret = read_command( & str_line_end );
+ if ( iret < 0 ) { return iret; }
+ } while ( ! str_line_end && iret );
+ if ( ! iret )
+ {
+ game_status |= flag_quit;
+ return 1;
+ }
+ }
+ else {
+#if defined(DEKUNOBOU)
+ if ( dek_ngame )
+ {
+ iret = dek_check();
+ goto tag;
+ }
+#endif
+
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL )
+ {
+ iret = sckt_check( sckt_csa );
+ goto tag;
+ }
+#endif
+
+#if defined(MNJ_LAN)
+ if ( sckt_mnj != SCKT_NULL )
+ {
+ iret = sckt_check( sckt_mnj );
+ goto tag;
+ }
+#endif
+ iret = check_input_buffer();
+
+#if defined(DEKUNOBOU) || defined(CSA_LAN) || defined(MNJ_LAN)
+ tag:
+#endif
+ if ( iret <= 0 ) { return iret; }
+
+ iret = read_command( & str_line_end );
+ if ( iret < 0 ) { return iret; }
+ if ( ! iret )
+ {
+ game_status |= flag_quit;
+ return 1;
+ }
+ if ( ! str_line_end ) { return 0; }
+ }
+ }
+
+ if ( str_line_end - str_buffer_cmdline + 1 >= SIZE_CMDLINE )
+ {
+ str_error = str_ovrflw_line;
+ memmove( str_buffer_cmdline, str_line_end + 1,
+ strlen( str_line_end + 1 ) + 1 );
+ return -2;
+ }
+
+ size = str_line_end - str_buffer_cmdline;
+ memcpy( str_cmdline, str_buffer_cmdline, size );
+ *( str_cmdline + size ) = '\0';
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame )
+ {
+ iret = dek_parse( str_cmdline, SIZE_CMDLINE );
+ if ( iret < 0 )
+ {
+ memmove( str_buffer_cmdline, str_line_end + 1,
+ strlen( str_line_end + 1 ) + 1 );
+ return iret;
+ }
+ }
+#endif
+
+ if ( is_wait )
+ {
+ out_file( NULL, "%s\n", str_cmdline );
+ memmove( str_buffer_cmdline, str_line_end + 1,
+ strlen( str_line_end + 1 ) + 1 );
+ }
+
+ return 1;
+}
+
+
+static int
+#if defined(NO_STDOUT) || defined(WIN32_PIPE)
+out_board0( FILE *pf, int piece, int i, int ito, int ifrom )
+#else
+out_board0( FILE *pf, int piece, int i, int ito, int ifrom, int is_promote )
+#endif
+{
+ int ch;
+#if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
+ int iret;
+#endif
+
+ if ( piece )
+ {
+ ch = piece < 0 ? '-' : '+';
+#if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
+ if ( i == ito && pf == stdout && ! ( game_status & flag_nostress ) )
+ {
+ iret = StdoutStress( is_promote, ifrom );
+ if ( iret < 0 )
+ {
+ fprintf( pf, "\n" );
+ return iret;
+ }
+ }
+#endif
+ fprintf( pf, "%c%s", ch, astr_table_piece[ abs( piece ) ] );
+#if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
+ if ( i == ito && pf == stdout && ! ( game_status & flag_nostress ) )
+ {
+ iret = StdoutNormal();
+ if ( iret < 0 )
+ {
+ fprintf( pf, "\n" );
+ return iret;
+ }
+ }
+#endif
+ }
+ else {
+ if ( ifrom < nsquare
+ && ( ifrom == i
+ || ( adirec[ito][ifrom]
+ && adirec[ito][ifrom] == adirec[ito][i]
+ && ( ( ito < i && i <= ifrom )
+ || ( ito > i && i >= ifrom ) ) ) ) )
+ {
+ fprintf( pf, " " );
+ }
+ else { fprintf( pf, " * " ); }
+ }
+
+ return 1;
+}
+
+
+#if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
+
+void
+out_beep( void )
+{
+ if ( game_status & flag_nobeep ) { return; }
+
+# if defined(_WIN32)
+ if ( ! MessageBeep( MB_OK ) )
+ {
+ out_warning( "Beep is not available." );
+ }
+# else
+ printf( "\007" );
+# endif
+}
+
+
+int
+stdout_normal( void )
+{
+# if defined(_WIN32)
+ HANDLE hStdout;
+ WORD wAttributes;
+
+ hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
+ if ( hStdout == INVALID_HANDLE_VALUE )
+ {
+ str_error = "GetStdHandle() faild";
+ return -1;
+ }
+
+ wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+ if ( ! SetConsoleTextAttribute( hStdout, wAttributes ) )
+ {
+ str_error = "SetConsoleTextAttribute() faild";
+ return -1;
+ }
+
+# else
+ printf( "\033[0m" );
+# endif
+ return 1;
+}
+
+
+int
+stdout_stress( int is_promote, int ifrom )
+{
+# if defined(_WIN32)
+ HANDLE hStdout;
+ WORD wAttributes;
+
+ hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
+ if ( hStdout == INVALID_HANDLE_VALUE )
+ {
+ str_error = "GetStdHandle() faild";
+ return -1;
+ }
+
+ if ( is_promote )
+ {
+ wAttributes = BACKGROUND_RED | BACKGROUND_INTENSITY;
+ }
+ else if ( ifrom >= nsquare )
+ {
+ wAttributes = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
+ }
+ else {
+ wAttributes = ( BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
+ | BACKGROUND_INTENSITY );
+ }
+ if ( ! SetConsoleTextAttribute( hStdout, wAttributes ) )
+ {
+ str_error = "SetConsoleTextAttribute() faild";
+ return -1;
+ }
+# else
+ if ( is_promote ) { printf( "\033[7;31m" ); }
+ else if ( ifrom >= nsquare ) { printf( "\033[7;34m" ); }
+ else { printf( "\033[7m" ); }
+# endif
+
+ return 1;
+}
+
+#endif /* no NO_STDOUT and no WIN32_PIPE */
+
+
+static void
+out_hand( FILE *pf, unsigned int hand, const char *str_prefix )
+{
+ out_hand0( pf, (int)I2HandPawn(hand), str_prefix, "00FU" );
+ out_hand0( pf, (int)I2HandLance(hand), str_prefix, "00KY" );
+ out_hand0( pf, (int)I2HandKnight(hand), str_prefix, "00KE" );
+ out_hand0( pf, (int)I2HandSilver(hand), str_prefix, "00GI" );
+ out_hand0( pf, (int)I2HandGold(hand), str_prefix, "00KI" );
+ out_hand0( pf, (int)I2HandBishop(hand), str_prefix, "00KA" );
+ out_hand0( pf, (int)I2HandRook(hand), str_prefix, "00HI" );
+}
+
+
+static void
+out_hand0( FILE *pf, int n, const char *str_prefix, const char *str )
+{
+ int i;
+
+ if ( n > 0 )
+ {
+ fprintf( pf, str_prefix );
+ for ( i = 0; i < n; i++ ) { fprintf( pf, str ); }
+ fprintf( pf, "\n" );
+ }
+}
+
+
+static int
+read_command( char ** pstr_line_end )
+{
+ char *str_end;
+ int count_byte, count_cmdbuff;
+
+ count_cmdbuff = (int)strlen( str_buffer_cmdline );
+ str_end = str_buffer_cmdline + count_cmdbuff;
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame )
+ {
+ count_byte = dek_in( str_end, SIZE_CMDLINE-1-count_cmdbuff );
+ if ( count_byte < 0 ) { return count_byte; }
+ goto tag;
+ }
+#endif
+
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL )
+ {
+ count_byte = sckt_in( sckt_csa, str_end, SIZE_CMDLINE-1-count_cmdbuff );
+ if ( count_byte < 0 ) { return count_byte; }
+ goto tag;
+ }
+#endif
+
+#if defined(MNJ_LAN)
+ if ( sckt_mnj != SCKT_NULL )
+ {
+ count_byte = sckt_in( sckt_mnj, str_end, SIZE_CMDLINE-1-count_cmdbuff );
+ if ( count_byte < 0 ) { return count_byte; }
+ goto tag;
+ }
+#endif
+
+ do { count_byte = (int)read( 0, str_end, SIZE_CMDBUFFER-1-count_cmdbuff ); }
+ while ( count_byte < 0 && errno == EINTR );
+
+ if ( count_byte < 0 )
+ {
+ str_error = "read() faild.";
+ return -1;
+ }
+ *( str_end + count_byte ) = '\0';
+
+#if defined(DEKUNOBOU) || defined(CSA_LAN) || defined(MNJ_LAN)
+ tag:
+#endif
+
+
+ *pstr_line_end = strchr( str_buffer_cmdline, '\n' );
+ if ( *pstr_line_end == NULL
+ && count_byte + count_cmdbuff + 1 >= SIZE_CMDLINE )
+ {
+ *str_buffer_cmdline = '\0';
+ str_error = str_ovrflw_line;
+ return -2;
+ }
+
+ return count_byte;
+}
+
+#if defined(_WIN32)
+
+static int
+check_input_buffer( void )
+{
+# if defined(WIN32_PIPE)
+ BOOL bSuccess;
+ HANDLE hHandle;
+ DWORD dwBytesRead, dwTotalBytesAvail, dwBytesLeftThisMessage;
+ char buf[1];
+
+ hHandle = GetStdHandle( STD_INPUT_HANDLE );
+ if ( hHandle == INVALID_HANDLE_VALUE )
+ {
+ str_error = "GetStdHandle() faild.";
+ return -1;
+ }
+ bSuccess = PeekNamedPipe( hHandle, buf, 1, &dwBytesRead, &dwTotalBytesAvail,
+ &dwBytesLeftThisMessage );
+ if ( ! bSuccess )
+ {
+ str_error = "PeekNamedPipe() faild.";
+ return -1;
+ }
+ if ( dwBytesRead ) { return 1; }
+ return 0;
+# else
+ return _kbhit();
+# endif
+}
+
+#else /* no _WIN32 */
+
+static int
+check_input_buffer( void )
+{
+ fd_set readfds;
+ struct timeval tv;
+ int iret;
+
+#if defined(__ICC)
+# pragma warning(disable:279)
+# pragma warning(disable:593)
+# pragma warning(disable:1469)
+#endif
+
+ FD_ZERO(&readfds);
+ FD_SET(0, &readfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ iret = select( 1, &readfds, NULL, NULL, &tv );
+ if ( iret == -1 )
+ {
+ str_error = "select() faild.";
+ return -1;
+ }
+ return iret;
+
+#if defined(__ICC)
+# pragma warning(default:279)
+# pragma warning(default:593)
+# pragma warning(default:1469)
+#endif
+}
+
+#endif /* no _WIN32 */
--- /dev/null
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+static void adjust_fmg( void );
+static int ini_hash( void );
+static int set_root_alpha( int nfail_low, int root_alpha_old );
+static int set_root_beta( int nfail_high, int root_beta_old );
+static int is_answer_right( unsigned int move );
+static const char *str_fail_high( int turn, int nfail_high );
+
+
+static int rep_book_prob( tree_t * restrict ptree )
+{
+ int i;
+
+ for ( i = root_nrep - 2; i >= 0; i -= 2 )
+ if ( ptree->rep_board_list[i] == HASH_KEY
+ && ptree->rep_hand_list[i] == HAND_B )
+ {
+ Out( "- book is ignored due to a repetition.\n" );
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int
+iterate( tree_t * restrict ptree, int flag )
+{
+ int value, iret, ply, is_hash_learn_stored;
+ unsigned int cpu_start;
+ int right_answer_made;
+
+ /* probe the opening book */
+ if ( pf_book != NULL && n_nobook_move < 7 && ! rep_book_prob( ptree ) )
+ {
+ int is_book_hit, i;
+ unsigned int elapsed;
+
+ is_book_hit = book_probe( ptree );
+ if ( is_book_hit < 0 ) { return is_book_hit; }
+
+ iret = get_elapsed( &elapsed );
+ if ( iret < 0 ) { return iret; }
+
+ Out( "- opening book is probed. (%ss)\n",
+ str_time_symple( elapsed - time_start ) );
+ if ( is_book_hit )
+ {
+ pv_close( ptree, 2, book_hit );
+ last_pv = ptree->pv[1];
+ last_root_value = 0;
+ n_nobook_move = 0;
+ if ( ! ( game_status & flag_puzzling ) )
+ {
+ for ( i = 0; i < HIST_SIZE; i++ )
+ {
+ ptree->hist_good[i] /= 256U;
+ ptree->hist_tried[i] /= 256U;
+ }
+ }
+
+ MnjOut( "pid=%d move=%s v=0b n=0 confident\n", mnj_posi_id,
+ str_CSA_move(ptree->pv[1].a[1]) );
+
+ return 1;
+ }
+ if ( ! ( game_status & ( flag_puzzling | flag_pondering ) ) )
+ {
+ n_nobook_move += 1;
+ }
+ }
+
+ /* initialize variables */
+ if ( get_cputime( &cpu_start ) < 0 ) { return -1; }
+
+ ptree->node_searched = 0;
+ ptree->nreject_done = 0;
+ ptree->nreject_tried = 0;
+ ptree->null_pruning_done = 0;
+ ptree->null_pruning_tried = 0;
+ ptree->check_extension_done = 0;
+ ptree->recap_extension_done = 0;
+ ptree->onerp_extension_done = 0;
+ ptree->nfour_fold_rep = 0;
+ ptree->nperpetual_check = 0;
+ ptree->nsuperior_rep = 0;
+ ptree->nrep_tried = 0;
+ ptree->neval_called = 0;
+ ptree->nquies_called = 0;
+ ptree->ntrans_always_hit = 0;
+ ptree->ntrans_prefer_hit = 0;
+ ptree->ntrans_probe = 0;
+ ptree->ntrans_exact = 0;
+ ptree->ntrans_lower = 0;
+ ptree->ntrans_upper = 0;
+ ptree->ntrans_superior_hit = 0;
+ ptree->ntrans_inferior_hit = 0;
+ ptree->fail_high = 0;
+ ptree->fail_high_first = 0;
+ ptree->current_move[0] = 0;
+ ptree->pv[0].a[0] = 0;
+ ptree->pv[0].a[1] = 0;
+ ptree->pv[0].depth = 0;
+ ptree->pv[0].length = 0;
+ iteration_depth = 0;
+ easy_value = 0;
+ easy_abs = 0;
+ right_answer_made = 0;
+ is_hash_learn_stored = 0;
+ root_abort = 0;
+ root_nmove = 0;
+ root_value = -score_bound;
+ root_alpha = -score_bound;
+ root_beta = score_bound;
+ root_move_cap = 0;
+ node_last_check = 0;
+ time_last_eff_search = time_start;
+ time_last_check = time_start;
+ game_status &= ~( flag_move_now | flag_suspend
+ | flag_quit_ponder | flag_search_error );
+#if defined(DBG_EASY)
+ easy_move = 0;
+#endif
+
+#if defined(TLP)
+ ptree->tlp_abort = 0;
+ tlp_nsplit = 0;
+ tlp_nabort = 0;
+ tlp_nslot = 0;
+#endif
+
+#if defined(MPV)
+ if ( ! ( game_status & flag_puzzling ) && mpv_num > 1 )
+ {
+ int i;
+
+ for ( i = 0; i < 2*mpv_num+1; i++ ) { mpv_pv[i].length = 0; }
+
+ last_pv.a[0] = 0;
+ last_pv.a[1] = 0;
+ last_pv.depth = 0;
+ last_pv.length = 0;
+ last_root_value = 0;
+
+ root_mpv = 1;
+ }
+ else { root_mpv = 0; }
+#endif
+
+
+ for ( ply = 0; ply < PLY_MAX; ply++ )
+ {
+ ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2 = 0U;
+ ptree->killers[ply].no1 = ptree->killers[ply].no2 = 0x0U;
+ }
+
+ {
+ unsigned int u = node_per_second / 16U;
+ if ( u > TIME_CHECK_MAX_NODE ) { u = TIME_CHECK_MAX_NODE; }
+ else if ( u < TIME_CHECK_MIN_NODE ) { u = TIME_CHECK_MIN_NODE; }
+ node_next_signal = u;
+ }
+
+ set_search_limit_time( root_turn );
+ adjust_fmg();
+
+ /* look up last pv. */
+ if ( last_pv.length )
+ {
+ Out( "- a pv was found in the previous search result.\n" );
+
+ iteration_depth = last_pv.depth;
+ ptree->pv[0] = last_pv;
+ ptree->pv[0].type = prev_solution;
+ root_value = root_turn ? -last_root_value : last_root_value;
+ out_pv( ptree, root_value, root_turn, 0 );
+ Out( "\n" );
+ }
+
+ /* probe the transposition table, since last pv is not available. */
+ if ( ! last_pv.length
+#if defined(MPV)
+ && ! root_mpv
+#endif
+ )
+ {
+ unsigned int value_type;
+ int alpha, beta;
+
+ iret = ini_hash();
+ if ( iret < 0 ) { return iret; }
+ is_hash_learn_stored = 1;
+
+ value = INT_MIN;
+ for ( ply = 1; ply < PLY_MAX - 10; ply++ )
+ {
+ alpha = -score_bound;
+ beta = score_bound;
+
+ value_type = hash_probe( ptree, 1, ply*PLY_INC+PLY_INC/2,
+ root_turn, alpha, beta, 0 );
+ if ( value_type != value_exact ) { break; }
+ value = HASH_VALUE;
+ }
+
+ if ( -score_bound < value )
+ {
+ Out( "- a pv was peeked through the transposition table.\n" );
+ iteration_depth = ply-1;
+ ptree->pv[0].depth = (unsigned char)(ply-1);
+ ptree->pv[0].type = hash_hit;
+ root_value = value;
+ out_pv( ptree, value, root_turn, 0 );
+ Out( "\n" );
+
+ if ( ! ptree->pv[0].length )
+ {
+ iteration_depth = 0;
+ ptree->pv[0].depth = 0;
+ root_value = -score_bound;
+#if ! defined(MINIMUM)
+ out_warning( "PEEK FAILED!!!" );
+#endif
+ }
+ }
+ }
+
+ /* root move generation */
+ {
+ unsigned int elapsed;
+
+ Out( "- root move generation" );
+ value = make_root_move_list( ptree, flag );
+ if ( game_status & flag_search_error ) { return -1; }
+ if ( game_status & ( flag_quit | flag_quit_ponder | flag_suspend ) )
+ {
+ return 1;
+ }
+
+ if ( ! root_nmove )
+ {
+ str_error = "No legal moves to search";
+ return -2;
+ }
+
+ if ( ! ptree->pv[0].length || ptree->pv[0].a[1] != root_move_list[0].move )
+ {
+ iteration_depth = 0;
+ ptree->pv[0].a[1] = root_move_list[0].move;
+ ptree->pv[0].length = 1;
+ ptree->pv[0].depth = 1;
+ ptree->pv[0].type = no_rep;
+ root_value = value;
+ }
+
+#if defined(MPV)
+ if ( root_mpv )
+ {
+ if ( root_nmove == 1 ) { root_mpv = 0; }
+ easy_abs = 0;
+ }
+#endif
+
+ if ( get_elapsed( &elapsed ) < 0 ) { return -1; }
+ Out( " ... done (%d moves, %ss)\n",
+ root_nmove, str_time_symple( elapsed - time_start ) );
+ }
+
+
+ /* save preliminary result */
+ assert( root_value != -score_bound );
+ last_root_value = root_turn ? -root_value : root_value;
+ last_pv = ptree->pv[0];
+
+#if defined(MNJ_LAN)
+ if ( sckt_mnj != SCKT_NULL )
+ {
+ const char *str = ( root_nmove == 1 ) ? "confident" : "";
+
+ MnjOut( "pid=%d move=%s v=%de n=%" PRIu64 " %s\n",
+ mnj_posi_id, str_CSA_move(ptree->pv[0].a[1]), root_value,
+ ptree->node_searched, str );
+ }
+#endif
+
+ /* return, if previous pv is long enough */
+ if ( abs(root_value) > score_max_eval
+ || iteration_depth >= depth_limit
+ || ( ( game_status & flag_puzzling )
+ && ( root_nmove == 1 || ptree->pv[0].depth > 4 ) ) )
+ {
+ return 1;
+ }
+
+ if ( ! is_hash_learn_stored )
+ {
+ iret = ini_hash();
+ if ( iret < 0 ) { return iret; }
+ }
+
+ /* iterative deepening search */
+#if defined(TLP)
+ iret = tlp_start();
+ if ( iret < 0 ) { return iret; }
+#endif
+ iteration_depth += 1;
+ root_beta = set_root_beta( 0, root_value );
+ root_alpha = set_root_alpha( 0, root_value );
+ root_value = root_alpha;
+ add_rejections( ptree, root_turn, 1 );
+ Out( "- drive an iterative deepening search starting from depth %d\n",
+ iteration_depth );
+
+ for ( ; iteration_depth < 30/*PLY_MAX-10*/; iteration_depth++ ) {
+
+ MnjOut( "pid=%d d=%d\n", mnj_posi_id, iteration_depth );
+
+
+ if ( get_elapsed( &time_last_search ) < 0 ) { return -1; }
+
+#if defined(MPV)
+ if ( root_mpv )
+ {
+ int i;
+ i = ( root_nmove < mpv_num ) ? root_nmove : mpv_num;
+ for ( ; i < mpv_num*2; i++ ) { mpv_pv[i].length = 0; }
+ }
+#endif
+
+ {
+ unsigned int move;
+ int tt, i, n;
+
+ tt = root_turn;
+ for ( ply = 1; ply <= ptree->pv[0].length; ply++ )
+ {
+ move = ptree->pv[0].a[ply];
+ if ( ! is_move_valid( ptree, move, tt ) )
+ {
+#if ! defined(MINIMUM)
+ out_warning( "Old pv has an illegal move! ply=%d, move=%s",
+ ply, str_CSA_move(move) );
+#endif
+ break;
+ }
+ MakeMove( tt, move, ply );
+ if ( InCheck(tt) )
+ {
+#if ! defined(MINIMUM)
+ out_warning( "Old pv has an illegal evasion! ply=%d, move=%s",
+ ply, str_CSA_move(move) );
+#endif
+ UnMakeMove( tt, move, ply );
+ break;
+ }
+ tt = Flip(tt);
+ }
+ for ( ply--; ply > 0; ply-- )
+ {
+ tt = Flip(tt);
+ move = ptree->pv[0].a[ply];
+ UnMakeMove( tt, move, ply );
+ hash_store_pv( ptree, move, tt );
+ }
+
+ root_nfail_high = 0;
+ root_nfail_low = 0;
+
+ n = root_nmove;
+ root_move_list[0].status = flag_first;
+ for ( i = 1; i < n; i++ ) { root_move_list[i].status = 0; }
+ }
+
+ /* a trial of searches */
+ for ( ;; ) {
+ value = searchr( ptree, root_alpha, root_beta, root_turn,
+ iteration_depth*PLY_INC + PLY_INC/2 );
+ if ( game_status & flag_search_error ) { return -1; }
+ if ( root_abort ) { break; }
+
+ assert( abs(value) < score_foul );
+
+ if ( root_beta <= value )
+ {
+ const char *str_move;
+ const char *str;
+ double dvalue;
+
+ root_move_list[0].status &= ~flag_searched;
+ root_move_list[0].status |= flag_failhigh;
+ dvalue = (double)( root_turn ? -root_beta : root_beta );
+
+ do { root_beta = set_root_beta( ++root_nfail_high, root_beta ); }
+ while ( value >= root_beta );
+
+ str = str_time_symple( time_last_result - time_start );
+ if ( root_move_list[0].status & flag_first )
+ {
+ Out( "(%2d)%6s %7.2f ", iteration_depth, str, dvalue / 100.0 );
+ }
+ else { Out( " %6s %7.2f ", str, dvalue / 100.0 ); }
+
+ str = str_fail_high( root_turn, root_nfail_high );
+
+ MnjOut( "pid=%d move=%s v=%dl n=%" PRIu64 "\n", mnj_posi_id,
+ str_CSA_move(ptree->pv[1].a[1]), root_beta,
+ ptree->node_searched );
+
+ str_move = str_CSA_move_plus( ptree, ptree->pv[1].a[1], 1,
+ root_turn );
+ Out( " 1.%c%s [%s!]\n", ach_turn[root_turn], str_move, str );
+
+
+ if ( game_status & flag_pondering )
+ {
+ OutCsaShogi( "info%+.2f %c%s %c%s [%s!]\n",
+ dvalue / 100.0, ach_turn[Flip(root_turn)],
+ str_CSA_move(ponder_move),
+ ach_turn[root_turn], str_move, str );
+ }
+ else {
+ OutCsaShogi( "info%+.2f %c%s [%s!]\n", dvalue / 100.0,
+ ach_turn[root_turn], str_move, str );
+ }
+ }
+ else if ( value <= root_alpha )
+ {
+ const char *str_move;
+ const char *str;
+ unsigned int time_elapsed;
+ double dvalue;
+
+ if ( ! ( root_move_list[0].status & flag_first ) )
+ {
+ root_value = root_alpha;
+ break;
+ }
+
+ root_move_list[0].status &= ~flag_searched;
+ root_move_list[0].status |= flag_faillow;
+ dvalue = (double)( root_turn ? -root_alpha : root_alpha );
+
+ if ( get_elapsed( &time_elapsed ) < 0 ) { return -1; }
+
+ do { root_alpha = set_root_alpha( ++root_nfail_low, root_alpha ); }
+ while ( value <= root_alpha );
+ root_value = root_alpha;
+ str = str_time_symple( time_elapsed - time_start );
+ Out( "(%2d)%6s %7.2f ", iteration_depth, str, dvalue / 100.0 );
+
+ str = str_fail_high( Flip(root_turn), root_nfail_low );
+ str_move = str_CSA_move_plus( ptree, root_move_list[0].move, 1,
+ root_turn );
+ Out( " 1.%c%s [%s?]\n", ach_turn[root_turn], str_move, str );
+ if ( game_status & flag_pondering )
+ {
+ OutCsaShogi( "info%+.2f %c%s %c%s [%s?]\n",
+ dvalue / 100.0, ach_turn[Flip(root_turn)],
+ str_CSA_move(ponder_move),
+ ach_turn[root_turn], str_move, str );
+ }
+ else {
+ OutCsaShogi( "info%+.2f %c%s [%s?]\n", dvalue / 100.0,
+ ach_turn[root_turn], str_move, str );
+ }
+ }
+ else { break; }
+ }
+
+ /* the trial of search ended */
+ if ( root_alpha < root_value && root_value < root_beta )
+ {
+ last_root_value = root_turn ? - root_value : root_value;
+ last_pv = ptree->pv[0];
+ }
+
+ if ( root_abort ) { break; }
+
+ if ( root_alpha < root_value && root_value < root_beta )
+ {
+#if ! defined(MINIMUM)
+ {
+ int i, n;
+ n = root_nmove;
+ for ( i = 0; i < n; i++ )
+ {
+ if ( root_move_list[i].status & flag_searched ) { continue; }
+ out_warning( "A root move %s is ignored\n",
+ str_CSA_move(root_move_list[i].move) );
+ }
+ }
+#endif
+
+ if ( ( game_status & flag_problem ) && depth_limit == PLY_MAX )
+ {
+ if ( is_answer_right( ptree->pv[0].a[1] ) )
+ {
+ if ( right_answer_made > 1 && iteration_depth > 3 ) { break; }
+ right_answer_made++;
+ }
+ else { right_answer_made = 0; }
+ }
+
+ if ( abs(value) > score_max_eval ) { break; }
+ if ( iteration_depth >= depth_limit ) { break; }
+
+ root_beta = set_root_beta( 0, value );
+ root_alpha = set_root_alpha( 0, value );
+ root_value = root_alpha;
+ }
+#if ! defined(MINIMUM)
+ else { out_warning(( "SEARCH INSTABILITY IS DETECTED!!!" )); }
+#endif
+
+ /* shell sort */
+ {
+ root_move_t root_move_swap;
+ const int n = root_nmove;
+ uint64_t sortv;
+ int i, j, k, h;
+
+ for ( k = SHELL_H_LEN - 1; k >= 0; k-- )
+ {
+ h = ashell_h[k];
+ for ( i = n-h-1; i > 0; i-- )
+ {
+ root_move_swap = root_move_list[i];
+ sortv = root_move_list[i].nodes;
+ for ( j = i+h; j < n && root_move_list[j].nodes > sortv; j += h )
+ {
+ root_move_list[j-h] = root_move_list[j];
+ }
+ root_move_list[j-h] = root_move_swap;
+ }
+ }
+ }
+ }
+
+ /* iteration ended */
+ sub_rejections( ptree, root_turn, 1 );
+
+ if ( game_status & flag_problem )
+ {
+ if ( is_answer_right( ptree->pv[0].a[1] ) )
+ {
+ right_answer_made = 1;
+ }
+ else { right_answer_made = 0; }
+ }
+
+ {
+ int i;
+
+ for ( i = 0; i < HIST_SIZE; i++ )
+ {
+ ptree->hist_good[i] /= 256U;
+ ptree->hist_tried[i] /= 256U;
+ }
+ }
+ /* prunings and extentions-statistics */
+ {
+ double drep, dreject, dhash, dnull, dfh1st;
+
+ drep = (double)ptree->nperpetual_check;
+ drep += (double)ptree->nfour_fold_rep;
+ drep += (double)ptree->nsuperior_rep;
+ drep *= 100.0 / (double)( ptree->nrep_tried + 1 );
+
+ dreject = 100.0 * (double)ptree->nreject_done;
+ dreject /= (double)( ptree->nreject_tried + 1 );
+
+ dhash = (double)ptree->ntrans_exact;
+ dhash += (double)ptree->ntrans_inferior_hit;
+ dhash += (double)ptree->ntrans_superior_hit;
+ dhash += (double)ptree->ntrans_upper;
+ dhash += (double)ptree->ntrans_lower;
+ dhash *= 100.0 / (double)( ptree->ntrans_probe + 1 );
+
+ dnull = 100.0 * (double)ptree->null_pruning_done;
+ dnull /= (double)( ptree->null_pruning_tried + 1 );
+
+ dfh1st = 100.0 * (double)ptree->fail_high_first;
+ dfh1st /= (double)( ptree->fail_high + 1 );
+
+ Out( " pruning -> rep=%4.2f%% reject=%4.2f%%\n", drep, dreject );
+
+ Out( " pruning -> hash=%2.0f%% null=%2.0f%% fh1st=%4.1f%%\n",
+ dhash, dnull, dfh1st );
+
+ Out( " extension-> chk=%u recap=%u 1rep=%u\n",
+ ptree->check_extension_done, ptree->recap_extension_done,
+ ptree->onerp_extension_done );
+ }
+
+ /* futility threashold */
+#if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
+ {
+ int misc = fmg_misc;
+ int drop = fmg_drop;
+ int cap = fmg_cap;
+ int mt = fmg_mt;
+ int misc_k = fmg_misc_king;
+ int cap_k = fmg_cap_king;
+ Out( " futility -> misc=%d drop=%d cap=%d mt=%d misc(k)=%d cap(k)=%d\n",
+ misc, drop, cap, mt, misc_k, cap_k );
+ }
+#endif
+
+ /* hashing-statistics */
+ {
+ double dalways, dprefer, dsupe, dinfe;
+ double dlower, dupper, dsat;
+ uint64_t word2;
+ int ntrans_table, i, n;
+
+ ntrans_table = 1 << log2_ntrans_table;
+ if ( ntrans_table > 8192 ) { ntrans_table = 8192; }
+
+ for ( i = 0, n = 0; i < ntrans_table; i++ )
+ {
+ word2 = ptrans_table[i].prefer.word2;
+ SignKey( word2, ptrans_table[i].prefer.word1 );
+ if ( trans_table_age == ( 7 & (int)word2 ) ) { n++; }
+
+ word2 = ptrans_table[i].always[0].word2;
+ SignKey( word2, ptrans_table[i].always[0].word1 );
+ if ( trans_table_age == ( 7 & (int)word2 ) ) { n++; }
+
+ word2 = ptrans_table[i].always[1].word2;
+ SignKey( word2, ptrans_table[i].always[1].word1 );
+ if ( trans_table_age == ( 7 & (int)word2 ) ) { n++; }
+ }
+
+ dalways = 100.0 * (double)ptree->ntrans_always_hit;
+ dalways /= (double)( ptree->ntrans_probe + 1 );
+
+ dprefer = 100.0 * (double)ptree->ntrans_prefer_hit;
+ dprefer /= (double)( ptree->ntrans_probe + 1 );
+
+ dsupe = 100.0 * (double)ptree->ntrans_superior_hit;
+ dsupe /= (double)( ptree->ntrans_probe + 1 );
+
+ dinfe = 100.0 * (double)ptree->ntrans_inferior_hit;
+ dinfe /= (double)( ptree->ntrans_probe + 1 );
+
+ Out( " hashing -> always=%2.0f%% prefer=%2.0f%% supe=%4.2f%% "
+ "infe=%4.2f%%\n", dalways, dprefer, dsupe, dinfe );
+
+ dlower = 100.0 * (double)ptree->ntrans_lower;
+ dlower /= (double)( ptree->ntrans_probe + 1 );
+
+ dupper = 100.0 * (double)ptree->ntrans_upper;
+ dupper /= (double)( ptree->ntrans_probe + 1 );
+
+ dsat = 100.0 * (double)n;
+ dsat /= (double)( 3 * ntrans_table );
+
+ OutCsaShogi( "statsatu=%.0f", dsat );
+ Out( " hashing -> "
+ "exact=%d lower=%2.0f%% upper=%4.2f%% sat=%2.0f%% age=%d\n",
+ ptree->ntrans_exact, dlower, dupper, dsat, trans_table_age );
+ if ( dsat > 9.0 ) { trans_table_age = ( trans_table_age + 1 ) & 0x7; }
+ }
+
+#if defined(TLP)
+ if ( tlp_max > 1 )
+ {
+ Out( " threading-> split=%d abort=%d slot=%d\n",
+ tlp_nsplit, tlp_nabort, tlp_nslot+1 );
+ if ( tlp_nslot+1 == TLP_NUM_WORK )
+ {
+ out_warning( "THREAD WORK AREA IS USED UP!!!" );
+ }
+ }
+#endif
+
+ {
+ double dcpu_percent, dnps, dmat;
+ unsigned int cpu, elapsed;
+
+ Out( " n=%" PRIu64 " quies=%u eval=%u rep=%u %u(chk) %u(supe)\n",
+ ptree->node_searched, ptree->nquies_called, ptree->neval_called,
+ ptree->nfour_fold_rep, ptree->nperpetual_check,
+ ptree->nsuperior_rep );
+
+ if ( get_cputime( &cpu ) < 0 ) { return -1; }
+ if ( get_elapsed( &elapsed ) < 0 ) { return -1; }
+
+ cpu -= cpu_start;
+ elapsed -= time_start;
+
+ dcpu_percent = 100.0 * (double)cpu;
+ dcpu_percent /= (double)( elapsed + 1U );
+
+ dnps = 1000.0 * (double)ptree->node_searched;
+ dnps /= (double)( elapsed + 1U );
+
+#if defined(TLP)
+ {
+ double n = (double)tlp_max;
+ node_per_second = (unsigned int)( ( dnps + 0.5 ) / n );
+ }
+#else
+ node_per_second = (unsigned int)( dnps + 0.5 );
+#endif
+
+ dmat = (double)MATERIAL;
+ dmat /= (double)MT_CAP_PAWN;
+
+ OutCsaShogi( " cpu=%.0f nps=%.2f\n", dcpu_percent, dnps / 1e3 );
+ Out( " time=%s ", str_time_symple( elapsed ) );
+ Out( "cpu=%3.0f%% mat=%.1f nps=%.2fK", dcpu_percent, dmat, dnps / 1e3 );
+ Out( " time_eff=%s\n\n",
+ str_time_symple( time_last_eff_search - time_start ) );
+ }
+
+ if ( ( game_status & flag_problem ) && ! right_answer_made ) { iret = 0; }
+ else { iret = 1; }
+
+ return iret;
+}
+
+
+static int
+ini_hash( void )
+{
+ unsigned int elapsed;
+ int iret;
+
+ if ( time_limit < 150U ) { return 1; }
+
+ iret = all_hash_learn_store();
+ if ( iret < 0 ) { return iret; }
+ if ( iret )
+ {
+ if ( get_elapsed( &elapsed ) < 0 ) { return -1; }
+ Out( "- load learnt hash values (%ss)\n",
+ str_time_symple( elapsed - time_start ) );
+ }
+
+ return 1;
+}
+
+
+static void
+adjust_fmg( void )
+{
+ int misc, cap, drop, mt, misc_king, cap_king;
+
+ misc = fmg_misc - FMG_MG / 2;
+ cap = fmg_cap - FMG_MG / 2;
+ drop = fmg_drop - FMG_MG / 2;
+ misc_king = fmg_misc_king - FMG_MG_KING / 2;
+ cap_king = fmg_cap_king - FMG_MG_KING / 2;
+ mt = fmg_mt - FMG_MG_MT / 2;
+
+ fmg_misc = ( misc < FMG_MISC ) ? FMG_MISC : misc;
+ fmg_cap = ( cap < FMG_CAP ) ? FMG_CAP : cap;
+ fmg_drop = ( drop < FMG_DROP ) ? FMG_DROP : drop;
+ fmg_misc_king = ( misc_king < FMG_MISC_KING ) ? FMG_MISC_KING : misc_king;
+ fmg_cap_king = ( cap_king < FMG_CAP_KING ) ? FMG_CAP_KING : cap_king;
+ fmg_mt = ( mt < FMG_MT ) ? FMG_MT : mt;
+}
+
+
+static int
+set_root_beta( int nfail_high, int root_beta_old )
+{
+ int aspiration_hwdth, aspiration_fail1;
+
+ if ( time_max_limit != time_limit )
+ {
+ aspiration_hwdth = MT_CAP_DRAGON / 8;
+ aspiration_fail1 = MT_CAP_DRAGON / 2;
+ }
+ else {
+ aspiration_hwdth = MT_CAP_DRAGON / 4;
+ aspiration_fail1 = ( MT_CAP_DRAGON * 3 ) / 4;
+ }
+
+ switch ( nfail_high )
+ {
+ case 0: root_beta_old += aspiration_hwdth; break;
+ case 1: root_beta_old += aspiration_fail1 - aspiration_hwdth; break;
+ case 2: root_beta_old = score_bound; break;
+ default:
+ out_error( "Error at set_root_beta!" );
+ exit(1);
+ }
+ if ( root_beta_old > score_max_eval ) { root_beta_old = score_bound; }
+
+ return root_beta_old;
+}
+
+
+static int
+set_root_alpha( int nfail_low, int root_alpha_old )
+{
+ int aspiration_hwdth, aspiration_fail1;
+
+ if ( time_max_limit != time_limit )
+ {
+ aspiration_hwdth = MT_CAP_DRAGON / 8;
+ aspiration_fail1 = MT_CAP_DRAGON / 2;
+ }
+ else {
+ aspiration_hwdth = MT_CAP_DRAGON / 4;
+ aspiration_fail1 = ( MT_CAP_DRAGON * 3 ) / 4;
+ }
+
+ switch ( nfail_low )
+ {
+ case 0: root_alpha_old -= aspiration_hwdth; break;
+ case 1: root_alpha_old -= aspiration_fail1 - aspiration_hwdth; break;
+ case 2: root_alpha_old = -score_bound; break;
+ default:
+ out_error( "Error at set_root_alpha!" );
+ exit(1);
+ }
+ if ( root_alpha_old < -score_max_eval ) { root_alpha_old = -score_bound; }
+
+ return root_alpha_old;
+}
+
+
+static const char *
+str_fail_high( int turn, int nfail_high )
+{
+ const char *str;
+
+ if ( time_max_limit != time_limit )
+ {
+ if ( nfail_high == 1 ) { str = turn ? "-1" : "+1"; }
+ else { str = turn ? "-4" : "+4"; }
+ }
+ else {
+ if ( nfail_high == 1 ) { str = turn ? "-2" : "+2"; }
+ else { str = turn ? "-6" : "+6"; }
+ }
+ return str;
+}
+
+
+static int
+is_answer_right( unsigned int move )
+{
+ const char *str_anser;
+ const char *str_move;
+ int ianser, iret;
+
+ iret = 0;
+ str_move = str_CSA_move( move );
+
+ for ( ianser = 0; ianser < MAX_ANSWER; ianser++ )
+ {
+ str_anser = &( record_problems.info.str_move[ianser][0] );
+ if ( str_anser[0] == '\0' ) { break; }
+ if ( ! strcmp( str_anser+1, str_move ) )
+ {
+ iret = 1;
+ break;
+ }
+ }
+
+ return iret;
+}
--- /dev/null
+# 'book narrow' allows Bonanza to play only famous opening-lines.
+# Use this only when Bonanza plays a small number of games.
+book wide
+# book narrow
+
+# Set the time control to 15 minutes - 0 second, limit of depth to 18.
+limit time 15 0 18
+
+# Set the time margin to 200 miliseconds.
+time response 200
+
+# In the case of this example, Bonanza uses two threads to search the
+# best move.
+tlp num 2
+
+# Do pondering.
+ponder on
+
+# Set the size of the transposition table to 192 MBytes.
+hash 22
+
+# Set the resign threashold to 65535 if you do not want Bonanza resigns.
+resign 1500
+# resign 65535
+
+# connect "hostname" "port #" "login id" "login password" "num games"
+connect wdoor.c.u-tokyo.ac.jp 4081 YourID floodgate-900-0,Something 999
+
+# quit Bonanza.
+quit
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+#if defined(_WIN32)
+# include <process.h>
+#else
+# include <sched.h>
+#endif
+#include "shogi.h"
+
+#if ! defined(MINIMUM)
+
+# define SEARCH_DEPTH 2
+# define NUM_RESULT 8
+# define MAX_RECORD_LENGTH 1024
+# define DOT_INTERVAL 10
+# define MAX_BOOK_PLY 64
+# define NumBookCluster 256
+# define NumBookEntry 0x1000
+# define SIZE_PV_BUFFER 0x100000
+# define MOVE_VOID 0x80000000U
+# define Move2S(move) (unsigned short)((move) & 0x7fffU)
+
+
+typedef struct {
+ struct { uint64_t a,b; } cluster[NumBookCluster];
+} book_entry_t;
+
+typedef struct {
+
+ /* input */
+ tree_t *ptree;
+ book_entry_t *pbook_entry;
+ FILE *pf_tmp;
+ record_t *precord;
+ unsigned int max_games, id;
+ int nworker;
+
+ /* output */
+ uint64_t result[ NUM_RESULT ];
+ uint64_t num_moves_counted, num_moves, result_norm, num_nodes;
+ double target, target_out_window;
+ unsigned int illegal_moves, max_pos_buf;
+ int info;
+
+ /* work area */
+ unsigned int record_moves[ MAX_RECORD_LENGTH ];
+ unsigned int amove_legal[ MAX_LEGAL_MOVES ];
+ unsigned int record_length, pos_buf;
+ unsigned short buf[ SIZE_PV_BUFFER ];
+ int root_turn;
+
+} parse1_data_t;
+
+typedef struct {
+
+ /* input */
+ tree_t *ptree;
+ FILE *pf_tmp;
+ unsigned int id;
+ int nworker;
+
+ /* output */
+ param_t param;
+ uint64_t num_moves_counted;
+ double target;
+ int info;
+
+ /* work area */
+ unsigned short buf[ SIZE_PV_BUFFER ];
+ unsigned int pv[ PLY_MAX + 2 ];
+
+} parse2_data_t;
+
+# if defined(_WIN32)
+static unsigned int __stdcall parse1_worker( void *arg );
+static unsigned int __stdcall parse2_worker( void *arg );
+# else
+static void *parse1_worker( void *arg );
+static void *parse2_worker( void *arg );
+#endif
+static void ini_book( book_entry_t *pbook_entry );
+static void make_pv( parse1_data_t *pdata, unsigned int record_move );
+static int read_game( parse1_data_t *pdata );
+static int read_buf( unsigned short *buf, FILE *pf );
+static int calc_deriv( parse2_data_t *pdata, int pos_buf, int turn );
+static int learn_parse1( tree_t * restrict ptree, book_entry_t *pbook_entry,
+ FILE *pf_tmp, record_t *precord,
+ unsigned int max_games, double *ptarget_out_window,
+ double *pobj_norm, int tlp1 );
+static int learn_parse2( tree_t * restrict ptree, FILE *pf_tmp,
+ int nsteps, double target_out_window,
+ double obj_norm, int tlp2 );
+static int book_probe_learn( const tree_t * restrict ptree,
+ book_entry_t *pbook_entry, int ply,
+ unsigned int move );
+static int rep_check_learn( tree_t * restrict ptree, int ply );
+static unsigned int s2move( const tree_t * restrict ptree, unsigned int move,
+ int tt );
+static double func( double x );
+static double dfunc( double x );
+
+int
+learn( tree_t * restrict ptree, int is_ini, int nsteps, unsigned int max_games,
+ int max_iterations, int nworker1, int nworker2 )
+{
+ record_t record;
+ book_entry_t *pbook_entry;
+ FILE *pf_tmp;
+ double target_out_window, obj_norm;
+ int iret, niterations;
+
+ pbook_entry = memory_alloc( sizeof(book_entry_t) * NumBookEntry );
+ if ( pbook_entry == NULL ) { return -2; }
+
+ if ( is_ini )
+ {
+ fill_param_zero();
+ fmg_misc = fmg_cap = fmg_drop = fmg_mt = 0;
+ fmg_misc_king = fmg_cap_king = 0;
+ }
+ else {
+ fmg_misc = FMG_MISC;
+ fmg_cap = FMG_CAP;
+ fmg_drop = FMG_DROP;
+ fmg_mt = FMG_MT;
+ fmg_misc_king = FMG_MISC_KING;
+ fmg_cap_king = FMG_CAP_KING;
+ }
+
+ game_status |= flag_learning;
+ root_alpha = - ( score_max_eval + 1 );
+ root_beta = + ( score_max_eval + 1 );
+ root_abort = 0;
+ iret = 1;
+
+ for ( niterations = 1; niterations <= max_iterations; niterations++ )
+ {
+ Out( "\n Iteration %03d\n", niterations );
+
+ iret = record_open( &record, "records.csa", mode_read, NULL, NULL );
+ if ( iret < 0 ) { break; }
+
+ pf_tmp = file_open( "tmp.bin", "wb" );
+ if ( pf_tmp == NULL )
+ {
+ record_close( &record );
+ iret = -2;
+ break;
+ }
+
+ iret = learn_parse1( ptree, pbook_entry, pf_tmp, &record, max_games,
+ &target_out_window, &obj_norm, nworker1 );
+
+ if ( iret < 0 )
+ {
+ record_close( &record );
+ file_close( pf_tmp );
+ break;
+ }
+
+ iret = file_close( pf_tmp );
+ if ( iret < 0 )
+ {
+ record_close( &record );
+ break;
+ }
+
+ pf_tmp = file_open( "tmp.bin", "rb" );
+ if ( pf_tmp == NULL )
+ {
+ record_close( &record );
+ iret = -2;
+ break;
+ }
+
+ iret = learn_parse2( ptree, pf_tmp, nsteps, target_out_window, obj_norm,
+ nworker2 );
+ if ( iret < 0 )
+ {
+ file_close( pf_tmp );
+ record_close( &record );
+ break;
+ }
+
+ iret = file_close( pf_tmp );
+ if ( iret < 0 )
+ {
+ record_close( &record );
+ break;
+ }
+
+ iret = record_close( &record );
+ if ( iret < 0 ) { break; }
+
+ if ( ! ( game_status & flag_learning ) )
+ {
+ out_warning( "flag_learning is not set." );
+ }
+ }
+
+ memory_free( pbook_entry );
+ game_status &= ~flag_learning;
+
+ return iret;
+}
+
+
+static int
+learn_parse1( tree_t * restrict ptree, book_entry_t *pbook_entry, FILE *pf_tmp,
+ record_t *precord, unsigned int max_games,
+ double *ptarget_out_window, double *pobj_norm, int nworker )
+{
+ parse1_data_t *pdata[ TLP_MAX_THREADS ];
+ int i, id;
+
+ ini_book( pbook_entry );
+
+ for ( id = 0; id < nworker; id++ )
+ {
+ pdata[id] = memory_alloc( sizeof(parse1_data_t) );
+ if ( pdata[id] == NULL ) { return -1; }
+
+ pdata[id]->ptree = NULL;
+ pdata[id]->pbook_entry = pbook_entry;
+ pdata[id]->pf_tmp = pf_tmp;
+ pdata[id]->precord = precord;
+ pdata[id]->max_games = max_games;
+ pdata[id]->id = id;
+ pdata[id]->nworker = nworker;
+ }
+
+#if defined(TLP)
+ for ( id = 1; id < nworker; id++ )
+ {
+# if defined(_WIN32)
+ pdata[id]->ptree = tlp_atree_work + id;
+ if ( ! _beginthreadex( 0, 0, parse1_worker, pdata[id], 0, 0 ) )
+ {
+ str_error = "_beginthreadex() failed.";
+ return -1;
+ }
+# else
+ pthread_t pt;
+
+ pdata[id]->ptree = tlp_atree_work + id;
+ if ( pthread_create( &pt, &pthread_attr, parse1_worker, pdata[id] ) )
+ {
+ str_error = "pthread_create() failed.";
+ return -1;
+ }
+# endif
+ }
+#endif /* TLP */
+
+ pdata[0]->ptree = ptree;
+ parse1_worker( pdata[0] );
+
+#if defined(TLP)
+ while ( tlp_num ) { tlp_yield(); }
+#endif
+
+ for ( id = 0; id < nworker; id++ )
+ {
+ if ( pdata[id]->info < 0 ) { return -1; }
+ }
+
+ for ( id = 1; id < nworker; id++ )
+ {
+ for ( i = 0; i < NUM_RESULT; i++ )
+ {
+ pdata[0]->result[i] += pdata[id]->result[i];
+ }
+ pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
+ pdata[0]->num_moves += pdata[id]->num_moves;
+ pdata[0]->num_nodes += pdata[id]->num_nodes;
+ pdata[0]->result_norm += pdata[id]->result_norm;
+ pdata[0]->target += pdata[id]->target;
+ pdata[0]->target_out_window += pdata[id]->target_out_window;
+ pdata[0]->illegal_moves += pdata[id]->illegal_moves;
+ if ( pdata[0]->max_pos_buf < pdata[id]->max_pos_buf )
+ {
+ pdata[0]->max_pos_buf = pdata[id]->max_pos_buf;
+ }
+ }
+ if ( pdata[0]->result_norm == 0 ) { pdata[0]->result_norm = 1; }
+ if ( pdata[0]->num_moves == 0 ) { pdata[0]->num_moves = 1; }
+ *ptarget_out_window = pdata[0]->target_out_window;
+ *pobj_norm = (double)pdata[0]->num_moves;
+
+ {
+ double dtemp;
+ int misc, drop, cap, mt, misc_king, cap_king;
+
+ Out( " done\n" );
+ Out( " Number of Games : %u\n", precord->games );
+ Out( " Total Moves : %"PRIu64"\n",pdata[0]->num_moves );
+ Out( " Moves Counted : %"PRIu64"\n",pdata[0]->num_moves_counted);
+ Out( " Illegal Moves : %u\n", pdata[0]->illegal_moves );
+ Out( " Nodes Searched : %"PRIu64"\n",pdata[0]->num_nodes );
+ Out( " Max pos_buf : %x\n", pdata[0]->max_pos_buf );
+ Out( " Move Prediction :" );
+ for ( i = 0, dtemp = 0.0; i < NUM_RESULT; i++ )
+ {
+ dtemp += (double)pdata[0]->result[i] * 100.0;
+ Out( " %4.1f%%", dtemp / (double)pdata[0]->result_norm );
+ }
+ Out( "\n" );
+
+ pdata[0]->target /= *pobj_norm;
+ dtemp = *ptarget_out_window / *pobj_norm;
+ Out( " Target : %f (%f)\n", pdata[0]->target, dtemp );
+
+ misc = fmg_misc / 2;
+ drop = fmg_drop / 2;
+ cap = fmg_cap / 2;
+ mt = fmg_mt / 2;
+ misc_king = fmg_misc_king / 2;
+ cap_king = fmg_cap_king / 2;
+ Out( " Futility : misc=%d drop=%d cap=%d mt=%d misc(k)=%d "
+ "cap(k)=%d\n", misc, drop, cap, mt, misc_king, cap_king );
+ }
+
+ for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
+
+ return 1;
+}
+
+
+# if defined(_MSC_VER)
+static unsigned int __stdcall parse1_worker( void *arg )
+# else
+static void *parse1_worker( void *arg )
+#endif
+{
+ parse1_data_t *pdata;
+ tree_t *ptree;
+ unsigned int record_move;
+ int i, imove, iret;
+
+ iret = 0;
+ pdata = (parse1_data_t *)arg;
+ ptree = pdata->ptree;
+
+#if defined(TLP)
+ if ( pdata->nworker > 1 )
+ {
+ lock( &tlp_lock );
+ tlp_num += 1;
+ if ( pdata->id ) { Out( "hi from thread #%d\n", pdata->id ); }
+ unlock( &tlp_lock );
+ while ( tlp_num < pdata->nworker ) { tlp_yield(); }
+ }
+#endif
+
+ for ( i = 0; i < NUM_RESULT; i++ ) { pdata->result[i] = 0; }
+ pdata->num_moves_counted = 0;
+ pdata->num_moves = 0;
+ pdata->num_nodes = 0;
+ pdata->max_pos_buf = 0;
+ pdata->result_norm = 0;
+ pdata->record_length = 0;
+ pdata->illegal_moves = 0;
+ pdata->info = 0;
+ pdata->target = 0.0;
+ pdata->target_out_window = 0.0;
+
+ for ( ;; ) {
+ /* make results */
+ pdata->pos_buf = 2U;
+ for ( imove = 0; imove < (int)pdata->record_length; imove++ )
+ {
+ record_move = pdata->record_moves[imove];
+
+ pdata->buf[ pdata->pos_buf++ ] = Move2S(record_move);
+
+ if ( record_move & MOVE_VOID ) { record_move &= ~MOVE_VOID; }
+ else { make_pv( pdata, record_move ); }
+
+ pdata->buf[ pdata->pos_buf++ ] = 0;
+
+ MakeMove( pdata->root_turn, record_move, 1 );
+ pdata->root_turn = Flip( pdata->root_turn );
+ ptree->move_last[1] = ptree->move_last[0];
+ ptree->nsuc_check[0] = 0;
+ ptree->nsuc_check[1]
+ = (unsigned char)( InCheck( pdata->root_turn ) ? 1U : 0 );
+ }
+
+#if defined(TLP)
+ if ( pdata->nworker > 1 ) { lock( &tlp_lock ); }
+#endif
+
+ /* save results */
+ if ( pdata->record_length )
+ {
+ if ( pdata->pos_buf > pdata->max_pos_buf )
+ {
+ pdata->max_pos_buf = pdata->pos_buf;
+ }
+ pdata->buf[0] = (unsigned short)( pdata->pos_buf / 0x10000U );
+ pdata->buf[1] = (unsigned short)( pdata->pos_buf % 0x10000U );
+
+ if ( fwrite( pdata->buf, sizeof(unsigned short), pdata->pos_buf,
+ pdata->pf_tmp ) != pdata->pos_buf )
+ {
+ str_error = str_io_error;
+ iret = -2;
+ }
+ }
+
+ /* read next game */
+ while ( iret >= 0 ) {
+ iret = read_game( pdata );
+ if ( iret == 1 ) { break; } /* end of record */
+ if ( pdata->record_length ) { break; } /* read a record */
+ }
+
+#if defined(TLP)
+ if ( pdata->nworker > 1 ) { unlock( &tlp_lock ); }
+#endif
+
+ if ( iret < 0 ) { break; }
+ if ( iret == 1 ) { break; }
+ }
+
+#if defined(TLP)
+ if ( pdata->nworker > 1 )
+ {
+ lock( &tlp_lock );
+ tlp_num -= 1;
+ unlock( &tlp_lock );
+ }
+#endif
+
+ pdata->info = iret;
+ return 0;
+}
+
+
+static void
+make_pv( parse1_data_t *pdata, unsigned int record_move )
+{
+ double func_value;
+ tree_t *ptree;
+ unsigned int *pmove;
+ unsigned int move, pos_buf;
+ int i, imove, record_value, nth, nc, nmove_legal;
+ int value, alpha, beta, depth, ply, tt;
+
+ record_value = INT_MIN;
+ nc = 0;
+ nth = 0;
+ depth = PLY_INC * SEARCH_DEPTH + PLY_INC / 2;
+ tt = Flip(pdata->root_turn);
+ pos_buf = pdata->pos_buf;
+ ptree = pdata->ptree;
+ ptree->node_searched = 0;
+#if defined(TLP)
+ ptree->tlp_abort = 0;
+#endif
+ for ( ply = 0; ply < PLY_MAX; ply++ )
+ {
+ ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2 = 0U;
+ ptree->killers[ply].no1 = ptree->killers[ply].no2 = 0U;
+ }
+ for ( i = 0; i < HIST_SIZE; i++ )
+ {
+ ptree->hist_good[i] /= 256U;
+ ptree->hist_tried[i] /= 256U;
+ }
+
+ pmove = GenCaptures ( pdata->root_turn, pdata->amove_legal );
+ pmove = GenNoCaptures ( pdata->root_turn, pmove );
+ pmove = GenDrop ( pdata->root_turn, pmove );
+ pmove = GenCapNoProEx2 ( pdata->root_turn, pmove );
+ pmove = GenNoCapNoProEx2( pdata->root_turn, pmove );
+ nmove_legal = (int)( pmove - pdata->amove_legal );
+
+ for ( i = 0; pdata->amove_legal[i] != record_move; i++ );
+ move = pdata->amove_legal[0];
+ pdata->amove_legal[0] = pdata->amove_legal[i];
+ pdata->amove_legal[i] = move;
+
+ for ( imove = 0; imove < nmove_legal; imove++ ) {
+ move = pdata->amove_legal[imove];
+ if ( imove )
+ {
+ alpha = record_value - FV_WINDOW;
+ beta = record_value + FV_WINDOW;
+ if ( alpha < root_alpha ) { alpha = root_alpha; }
+ if ( beta > root_beta ) { beta = root_beta; }
+ }
+ else {
+ alpha = root_alpha;
+ beta = root_beta;
+ }
+
+ MakeMove( pdata->root_turn, move, 1 );
+ if ( InCheck(pdata->root_turn) )
+ {
+ UnMakeMove( pdata->root_turn, move, 1 );
+ continue;
+ }
+
+ if ( InCheck(tt) )
+ {
+ ptree->nsuc_check[2]
+ = (unsigned char)( ptree->nsuc_check[0] + 1U );
+ } else { ptree->nsuc_check[2] = 0; }
+
+ ptree->current_move[1] = move;
+ ptree->pv[1].type = no_rep;
+
+ value = -search( ptree, -beta, -alpha, tt, depth, 2,
+ node_do_mate | node_do_null | node_do_futile
+ | node_do_recap );
+
+ UnMakeMove( pdata->root_turn, move, 1 );
+
+ if ( abs(value) > score_mate1ply )
+ {
+ out_warning( "value is larger than mate1ply!" );
+ }
+
+ if ( imove )
+ {
+ func_value = func( value - record_value );
+ pdata->target += func_value;
+ pdata->num_moves += 1U;
+ if ( alpha < value && value < beta )
+ {
+ nc += 1;
+ }
+ else { pdata->target_out_window += func_value; }
+ if ( value >= record_value ) { nth += 1; }
+ }
+ else if ( alpha < value && value < beta )
+ {
+ nth += 1;
+ record_value = value;
+ }
+ else { break; } /* record move failed high or low. */
+
+ if ( alpha < value && value < beta )
+ {
+ pdata->buf[ pos_buf++ ] = Move2S(move);
+ for ( ply = 2; ply <= ptree->pv[1].length; ply++ )
+ {
+ pdata->buf[ pos_buf++ ] = Move2S(ptree->pv[1].a[ply]);
+ }
+ pdata->buf[ pos_buf - 1 ] |= 0x8000U;
+ }
+ }
+
+ if ( nth - 1 >= 0 )
+ {
+ pdata->result_norm += 1;
+ if ( nth-1 < NUM_RESULT ) { pdata->result[nth-1] += 1; }
+ }
+
+ if ( nc )
+ {
+ pdata->pos_buf = pos_buf;
+ pdata->num_moves_counted += nc;
+ }
+ pdata->num_nodes += ptree->node_searched;
+}
+
+
+static int
+read_game( parse1_data_t *pdata )
+{
+ tree_t *ptree;
+ tree_t tree;
+ unsigned int record_move;
+ int istatus, iret, imove;
+
+ ptree = & tree;
+ istatus = 0;
+ if ( pdata->precord->games == pdata->max_games ) { return 1; }
+
+ if ( pdata->precord->games == 0 ) { Out( " Parse 1 " ); }
+
+ if ( ! ( (pdata->precord->games+1) % DOT_INTERVAL ) )
+ {
+ if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 10 ) ) )
+ {
+ Out( "o" );
+ if ( ! ( (pdata->precord->games+1) % ( DOT_INTERVAL * 50 ) ) )
+ {
+ Out( "%7d\n ", pdata->precord->games+1 );
+ }
+ }
+ else { Out( "." ); }
+ }
+
+ for ( imove = 0; imove < MAX_RECORD_LENGTH; imove++ )
+ {
+ istatus = in_CSA( ptree, pdata->precord, &record_move,
+ flag_nomake_move | flag_detect_hang | flag_nofmargin );
+ if ( istatus < 0 )
+ {
+ pdata->illegal_moves += 1;
+ break;
+ }
+ if ( istatus >= record_eof ) { break; }
+
+ if ( ! imove
+ && ( root_turn != min_posi_no_handicap.turn_to_move
+ || HAND_B != min_posi_no_handicap.hand_black
+ || HAND_W != min_posi_no_handicap.hand_white
+ || memcmp( BOARD, min_posi_no_handicap.asquare, nsquare ) ) )
+ {
+ break;
+ }
+
+ if ( ! imove )
+ {
+ *(pdata->ptree) = *ptree;
+ pdata->root_turn = root_turn;
+ }
+
+ if ( rep_check_learn( ptree, 1 ) == four_fold_rep
+ || ( pdata->precord->moves < MAX_BOOK_PLY
+ && book_probe_learn( ptree, pdata->pbook_entry,
+ pdata->precord->moves, record_move ) ) )
+ {
+ pdata->record_moves[ imove ] = record_move | MOVE_VOID;
+ }
+ else { pdata->record_moves[ imove ] = record_move; }
+
+ iret = make_move_root( ptree, record_move, flag_rejections );
+ if ( iret < 0 ) { return iret; }
+ }
+
+ if ( istatus != record_next && istatus != record_eof )
+ {
+ istatus = record_wind( pdata->precord );
+ if ( istatus < 0 ) { return istatus; }
+ }
+
+ if ( ! imove && istatus == record_eof ) { return 1; }
+ pdata->record_length = imove;
+
+ return 0;
+}
+
+
+static int
+learn_parse2( tree_t * restrict ptree, FILE *pf_tmp, int nsteps,
+ double target_out_window, double obj_norm, int nworker )
+{
+ parse2_data_t *pdata[ TLP_MAX_THREADS ];
+ int istep, id;
+
+ for ( id = 0; id < nworker; id++ )
+ {
+ pdata[id] = memory_alloc( sizeof(parse2_data_t) );
+ if ( pdata[id] == NULL ) { return -1; }
+
+ pdata[id]->ptree = NULL;
+ pdata[id]->pf_tmp = pf_tmp;
+ pdata[id]->id = id;
+ pdata[id]->nworker = nworker;
+ }
+
+ Out( " Parse 2\n" );
+
+ istep = 0;
+ for ( ;; ) {
+
+#if defined(TLP)
+ for ( id = 1; id < nworker; id++ )
+ {
+# if defined(_WIN32)
+ pdata[id]->ptree = tlp_atree_work + id;
+ if ( ! _beginthreadex( 0, 0, parse2_worker, pdata[id], 0, 0 ) )
+ {
+ str_error = "_beginthreadex() failed.";
+ return -1;
+ }
+# else
+ pthread_t pt;
+
+ pdata[id]->ptree = tlp_atree_work + id;
+ if ( pthread_create( &pt, &pthread_attr, parse2_worker, pdata[id] ) )
+ {
+ str_error = "pthread_create() failed.";
+ return -1;
+ }
+# endif
+ }
+#endif /* TLP */
+
+ pdata[0]->ptree = ptree;
+ parse2_worker( pdata[0] );
+
+#if defined(TLP)
+ while ( tlp_num ) { tlp_yield(); }
+#endif
+
+ for ( id = 0; id < nworker; id++ )
+ {
+ if ( pdata[id]->info < 0 ) { return -1; }
+ }
+
+ for ( id = 1; id < nworker; id++ )
+ {
+ add_param( &pdata[0]->param, &pdata[id]->param );
+ pdata[0]->num_moves_counted += pdata[id]->num_moves_counted;
+ pdata[0]->target += pdata[id]->target;
+ }
+
+ if ( ! istep )
+ {
+ double target, penalty, objective_function;
+
+ penalty = calc_penalty() / obj_norm;
+ target = ( pdata[0]->target + target_out_window ) / obj_norm;
+ objective_function = target + penalty;
+ Out( " Moves Counted : %d\n", pdata[0]->num_moves_counted );
+ Out( " Objective Func. : %f %f %f\n",
+ objective_function, target, penalty );
+ Out( " Steps " );
+ }
+
+ param_sym( &pdata[0]->param );
+
+ renovate_param( &pdata[0]->param );
+ istep += 1;
+ if ( istep < nsteps ) { Out( "." ); }
+ else {
+ Out( ". done\n\n" );
+ break;
+ }
+ rewind( pf_tmp );
+ }
+ for ( id = 0; id < nworker; id++ ) { memory_free( pdata[id] ); }
+
+ return out_param();
+}
+
+
+# if defined(_MSC_VER)
+static unsigned int __stdcall parse2_worker( void *arg )
+# else
+static void *parse2_worker( void *arg )
+#endif
+{
+ parse2_data_t *pdata;
+ tree_t *ptree;
+ unsigned int record_move;
+ int iret, imove, nbuf, pos_buf, turn;
+
+ iret = 0;
+ pdata = (parse2_data_t *)arg;
+ ptree = pdata->ptree;
+
+#if defined(TLP)
+ if ( pdata->nworker > 1 )
+ {
+ lock( &tlp_lock );
+ tlp_num += 1;
+ unlock( &tlp_lock );
+ while ( tlp_num < pdata->nworker ) { tlp_yield(); }
+ }
+#endif
+
+ pdata->num_moves_counted = 0;
+ pdata->info = 0;
+ pdata->target = 0.0;
+ ini_param( &pdata->param );
+
+ for ( ;; ) {
+#if defined(TLP)
+ if ( pdata->nworker > 1 ) { lock( &tlp_lock ); }
+#endif
+ iret = read_buf( pdata->buf, pdata->pf_tmp );
+#if defined(TLP)
+ if ( pdata->nworker > 1 ) { unlock( &tlp_lock ); }
+#endif
+
+ if ( iret <= 0 ) { break; } /* 0: eof, -2: error */
+ nbuf = iret;
+
+ iret = ini_game( ptree, &min_posi_no_handicap, flag_nofmargin,
+ NULL, NULL );
+ if ( iret < 0 ) { break; }
+
+ turn = black;
+ pos_buf = 2;
+ for ( imove = 0; pos_buf < nbuf; imove++ )
+ {
+ record_move = s2move( ptree, pdata->buf[pos_buf++], turn );
+
+ if ( pdata->buf[pos_buf] )
+ {
+ pos_buf = calc_deriv( pdata, pos_buf, turn );
+ }
+ pos_buf += 1;
+
+ MakeMove( turn, record_move, 1 );
+ turn = Flip( turn );
+ ptree->move_last[1] = ptree->move_last[0];
+ ptree->nsuc_check[0] = 0;
+ ptree->nsuc_check[1]
+ = (unsigned char)( InCheck( turn ) ? 1U : 0 );
+ }
+ }
+
+#if defined(TLP)
+ if ( pdata->nworker > 1 )
+ {
+ lock( &tlp_lock );
+ tlp_num -= 1;
+ unlock( &tlp_lock );
+ }
+#endif
+
+ pdata->info = iret;
+ return 0;
+}
+
+
+static int
+read_buf( unsigned short *buf, FILE *pf )
+{
+ size_t size;
+
+ size = fread( buf, sizeof(unsigned short), 2, pf );
+ if ( ! size && feof( pf ) ) { return 0; }
+ if ( size != 2 )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ size = (size_t)buf[1] + (size_t)buf[0] * 0x10000 - 2;
+ if ( fread( buf+2, sizeof(unsigned short), size, pf ) != size )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ return (int)size;
+}
+
+
+static int
+calc_deriv( parse2_data_t *pdata, int pos0, int turn0 )
+{
+ double target, dT, sum_dT;
+ tree_t * restrict ptree;
+ const unsigned short *buf;
+ unsigned int nc;
+ int ply, turn, pv_length, pos, record_value, value;
+
+ ptree = pdata->ptree;
+ buf = pdata->buf;
+ nc = 0;
+ turn = turn0;
+ pos = pos0;
+ target = 0.0;
+ sum_dT = 0.0;
+
+ ply = 1;
+ for ( ;; ) {
+ pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
+ MakeMove( turn, pdata->pv[ply], ply );
+ turn = Flip( turn );
+ if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
+ ply += 1;
+ }
+ pv_length = ply;
+
+ record_value = evaluate( ptree, ply+1, turn );
+ if ( turn != turn0 ) { record_value = -record_value; }
+
+ for ( ;; ) {
+ turn = Flip( turn );
+ UnMakeMove( turn, pdata->pv[ply], ply );
+ if ( ply == 1 ) { break; }
+ ply -= 1;
+ }
+ pos += pv_length;
+
+ while ( buf[ pos ] ) {
+ ply = 1;
+ for ( ;; ) {
+ pdata->pv[ply] = s2move( ptree, buf[ pos+ply-1 ] & 0x7fffU, turn );
+ MakeMove( turn, pdata->pv[ply], ply );
+ turn = Flip( turn );
+ if ( buf[ pos+ply-1 ] & 0x8000U ) { break; }
+ ply += 1;
+ }
+ pv_length = ply;
+
+ value = evaluate( ptree, ply+1, turn );
+ if ( turn != turn0 ) { value = -value; }
+ target += func( value - record_value );
+
+ dT = dfunc( value - record_value );
+ if ( turn0 ) { dT = -dT; }
+ sum_dT += dT;
+ inc_param( ptree, &pdata->param, -dT );
+
+ for ( ;; ) {
+ turn = Flip( turn );
+ UnMakeMove( turn, pdata->pv[ply], ply );
+ if ( ply == 1 ) { break; }
+ ply -= 1;
+ }
+
+ pos += pv_length;
+ nc += 1;
+ }
+
+ ply = 1;
+ for ( ;; ) {
+ pdata->pv[ply] = s2move( ptree, buf[ pos0+ply-1 ] & 0x7fffU, turn );
+ MakeMove( turn, pdata->pv[ply], ply );
+ turn = Flip( turn );
+ if ( buf[ pos0+ply-1 ] & 0x8000U ) { break; }
+ ply += 1;
+ }
+
+ inc_param( ptree, &pdata->param, sum_dT );
+
+ for ( ;; ) {
+ turn = Flip( turn );
+ UnMakeMove( turn, pdata->pv[ply], ply );
+ if ( ply == 1 ) { break; }
+ ply -= 1;
+ }
+
+ pdata->num_moves_counted += nc;
+ pdata->target += target;
+
+ return pos;
+}
+
+
+static double
+func( double x )
+{
+ const double delta = (double)FV_WINDOW / 7.0;
+ double d;
+
+ if ( x < -FV_WINDOW ) { x = -FV_WINDOW; }
+ else if ( x > FV_WINDOW ) { x = FV_WINDOW; }
+ d = 1.0 / ( 1.0 + exp(-x/delta) );
+
+ return d;
+}
+
+
+static double
+dfunc( double x )
+{
+ const double delta = (double)FV_WINDOW / 7.0;
+ double dd, dn, dtemp, dret;
+
+ if ( x <= -FV_WINDOW ) { dret = 0.0; }
+ else if ( x >= FV_WINDOW ) { dret = 0.0; }
+ else {
+ dn = exp( - x / delta );
+ dtemp = dn + 1.0;
+ dd = delta * dtemp * dtemp;
+ dret = dn / dd;
+ }
+
+ return dret;
+}
+
+
+static unsigned int
+s2move( const tree_t * restrict ptree, unsigned int move, int tt )
+{
+ int from, to;
+
+ from = I2From(move);
+ if ( from < nsquare )
+ {
+ to = I2To(move);
+ move |= tt ? (Piece2Move(-BOARD[from])|Cap2Move( BOARD[to]))
+ : (Piece2Move( BOARD[from])|Cap2Move(-BOARD[to]));
+ }
+ return move;
+}
+
+
+static void
+ini_book( book_entry_t *pbook_entry )
+{
+ int i, j;
+
+ for ( i = 0; i < NumBookEntry; i++ )
+ for ( j = 0; j < NumBookCluster; j++ ) {
+ pbook_entry[i].cluster[j].a = (uint64_t)0;
+ pbook_entry[i].cluster[j].b = (uint64_t)0x1ffU << 41;
+ }
+}
+
+
+/*
+a: key 64 0
+
+b: ply 9 41
+ move 19 22
+ turn 1 21
+ hand 21 0
+*/
+static int
+book_probe_learn( const tree_t * restrict ptree,
+ book_entry_t *pbook_entry,
+ int ply, unsigned int move )
+{
+ book_entry_t *p;
+ int i, j;
+
+ move &= 0x7ffffU;
+ p = pbook_entry
+ + ((unsigned int)HASH_KEY & (unsigned int)(NumBookEntry-1));
+
+ for ( i = 0; i < NumBookCluster; i++ )
+ if ( p->cluster[i].a == HASH_KEY
+ && ((unsigned int)p->cluster[i].b & 0x1fffffU) == HAND_B
+ && ( (((unsigned int)p->cluster[i].b>>21) & 0x1U)
+ == (unsigned int)root_turn )
+ && ((unsigned int)(p->cluster[i].b>>22) & 0x7ffffU) == move ) {
+ return 1;
+ }
+
+ for ( i = 0; i < NumBookCluster; i++ )
+ if ( ( (unsigned int)( p->cluster[i].b >> 41 ) & 0x1ffU )
+ > (unsigned int)ply ) { break; }
+
+ if ( i < NumBookCluster ) {
+ for ( j = NumBookCluster-1; j > i; j-- ) {
+ p->cluster[j].a = p->cluster[j-1].a;
+ p->cluster[j].b = p->cluster[j-1].b;
+ }
+
+ p->cluster[i].a = HASH_KEY;
+ p->cluster[i].b
+ = ( (uint64_t)move<<22 ) | ( (uint64_t)ply << 41 )
+ | (uint64_t)( (root_turn<<21) | HAND_B );
+ }
+
+ return 0;
+}
+
+
+static int
+rep_check_learn( tree_t * restrict ptree, int ply )
+{
+ int n, i, imin;
+
+ n = root_nrep + ply - 1;
+ imin = n - REP_MAX_PLY;
+ if ( imin < 0 ) { imin = 0; }
+
+ for ( i = n-2; i >= imin; i -= 2 )
+ if ( ptree->rep_board_list[i] == HASH_KEY
+ && ptree->rep_hand_list[i] == HAND_B ) { return four_fold_rep; }
+
+ return no_rep;
+}
+
+#endif /* no MINIMUM */
--- /dev/null
+#include <stdlib.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+#include <assert.h>
+#include "shogi.h"
+
+#if ! defined(MINIMUM)
+
+#define GO_THROUGH_ALL_PARAMETERS_BY_FOO \
+ for ( i=0; i < nsquare*pos_n; i++ ) { Foo( pc_on_sq[0][i] ) } \
+ for ( i=0; i < nsquare*nsquare*kkp_end; i++ ) { Foo( kkp[0][0][i] ) }
+
+
+static void rmt( const double avalue[16], int pc );
+static void rparam( short *pv, float dv );
+static void fv_sym( void );
+static int brand( void );
+static int make_list( const tree_t * restrict ptree, int list0[52],
+ int list1[52], int anpiece[16], param_t * restrict pd,
+ float f );
+
+
+void
+ini_param( param_t *p )
+{
+ int i;
+
+ p->pawn = p->lance = p->knight = p->silver = 0.0;
+ p->gold = p->bishop = p->rook = p->pro_pawn = 0.0;
+ p->pro_lance = p->pro_knight = p->pro_silver = p->horse = 0.0;
+ p->dragon = 0.0;
+
+#define Foo(x) p->x = 0;
+ GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+}
+
+
+void
+add_param( param_t *p1, const param_t *p2 )
+{
+ int i;
+
+ p1->pawn += p2->pawn;
+ p1->lance += p2->lance;
+ p1->knight += p2->knight;
+ p1->silver += p2->silver;
+ p1->gold += p2->gold;
+ p1->bishop += p2->bishop;
+ p1->rook += p2->rook;
+ p1->pro_pawn += p2->pro_pawn;
+ p1->pro_lance += p2->pro_lance;
+ p1->pro_knight += p2->pro_knight;
+ p1->pro_silver += p2->pro_silver;
+ p1->horse += p2->horse;
+ p1->dragon += p2->dragon;
+
+#define Foo(x) p1->x += p2->x;
+ GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+}
+
+
+void
+fill_param_zero( void )
+{
+ int i;
+
+ p_value[15+pawn] = 100;
+ p_value[15+lance] = 300;
+ p_value[15+knight] = 300;
+ p_value[15+silver] = 400;
+ p_value[15+gold] = 500;
+ p_value[15+bishop] = 600;
+ p_value[15+rook] = 700;
+ p_value[15+pro_pawn] = 400;
+ p_value[15+pro_lance] = 400;
+ p_value[15+pro_knight] = 400;
+ p_value[15+pro_silver] = 500;
+ p_value[15+horse] = 800;
+ p_value[15+dragon] = 1000;
+
+#define Foo(x) x = 0;
+ GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+
+ set_derivative_param();
+}
+
+
+void
+param_sym( param_t *p )
+{
+ int q, r, il, ir, ir0, jl, jr, k0l, k0r, k1l, k1r;
+
+ for ( k0l = 0; k0l < nsquare; k0l++ ) {
+ q = k0l / nfile;
+ r = k0l % nfile;
+ k0r = q*nfile + nfile-1-r;
+ if ( k0l > k0r ) { continue; }
+
+ for ( il = 0; il < fe_end; il++ ) {
+ if ( il < fe_hand_end ) { ir0 = il; }
+ else {
+ q = ( il- fe_hand_end ) / nfile;
+ r = ( il- fe_hand_end ) % nfile;
+ ir0 = q*nfile + nfile-1-r + fe_hand_end;
+ }
+
+ for ( jl = 0; jl <= il; jl++ ) {
+ if ( jl < fe_hand_end )
+ {
+ ir = ir0;
+ jr = jl;
+ }
+ else {
+ q = ( jl - fe_hand_end ) / nfile;
+ r = ( jl - fe_hand_end ) % nfile;
+ jr = q*nfile + nfile-1-r + fe_hand_end;
+ if ( jr > ir0 )
+ {
+ ir = jr;
+ jr = ir0;
+ }
+ else { ir = ir0; }
+ }
+ if ( k0l == k0r && il*(il+1)/2+jl >= ir*(ir+1)/2+jr ) { continue; }
+
+ p->PcPcOnSq(k0l,il,jl)
+ = p->PcPcOnSq(k0r,ir,jr)
+ = p->PcPcOnSq(k0l,il,jl) + p->PcPcOnSq(k0r,ir,jr);
+ }
+ }
+ }
+
+ for ( k0l = 0; k0l < nsquare; k0l++ ) {
+ q = k0l / nfile;
+ r = k0l % nfile;
+ k0r = q*nfile + nfile-1-r;
+ if ( k0l > k0r ) { continue; }
+
+ for ( k1l = 0; k1l < nsquare; k1l++ ) {
+ q = k1l / nfile;
+ r = k1l % nfile;
+ k1r = q*nfile + nfile-1-r;
+ if ( k0l == k0r && k1l > k1r ) { continue; }
+
+ for ( il = 0; il < kkp_end; il++ ) {
+ if ( il < kkp_hand_end ) { ir = il; }
+ else {
+ q = ( il- kkp_hand_end ) / nfile;
+ r = ( il- kkp_hand_end ) % nfile;
+ ir = q*nfile + nfile-1-r + kkp_hand_end;
+ }
+ if ( k0l == k0r && k1l == k1r && il >= ir ) { continue; }
+
+ p->kkp[k0l][k1l][il]
+ = p->kkp[k0r][k1r][ir]
+ = p->kkp[k0l][k1l][il] + p->kkp[k0r][k1r][ir];
+ }
+ }
+ }
+}
+
+
+static void fv_sym( void )
+{
+ int q, r, il, ir, ir0, jl, jr, k0l, k0r, k1l, k1r;
+
+ for ( k0l = 0; k0l < nsquare; k0l++ ) {
+ q = k0l / nfile;
+ r = k0l % nfile;
+ k0r = q*nfile + nfile-1-r;
+ if ( k0l > k0r ) { continue; }
+
+ for ( il = 0; il < fe_end; il++ ) {
+ if ( il < fe_hand_end ) { ir0 = il; }
+ else {
+ q = ( il- fe_hand_end ) / nfile;
+ r = ( il- fe_hand_end ) % nfile;
+ ir0 = q*nfile + nfile-1-r + fe_hand_end;
+ }
+
+ for ( jl = 0; jl <= il; jl++ ) {
+ if ( jl < fe_hand_end )
+ {
+ ir = ir0;
+ jr = jl;
+ }
+ else {
+ q = ( jl - fe_hand_end ) / nfile;
+ r = ( jl - fe_hand_end ) % nfile;
+ jr = q*nfile + nfile-1-r + fe_hand_end;
+ if ( jr > ir0 )
+ {
+ ir = jr;
+ jr = ir0;
+ }
+ else { ir = ir0; }
+ }
+ if ( k0l == k0r && il*(il+1)/2+jl >= ir*(ir+1)/2+jr ) { continue; }
+
+ PcPcOnSq(k0l,il,jl) = PcPcOnSq(k0r,ir,jr);
+ }
+ }
+ }
+
+ for ( k0l = 0; k0l < nsquare; k0l++ ) {
+ q = k0l / nfile;
+ r = k0l % nfile;
+ k0r = q*nfile + nfile-1-r;
+ if ( k0l > k0r ) { continue; }
+
+ for ( k1l = 0; k1l < nsquare; k1l++ ) {
+ q = k1l / nfile;
+ r = k1l % nfile;
+ k1r = q*nfile + nfile-1-r;
+ if ( k0l == k0r && k1l > k1r ) { continue; }
+
+ for ( il = 0; il < kkp_end; il++ ) {
+ if ( il < kkp_hand_end ) { ir = il; }
+ else {
+ q = ( il- kkp_hand_end ) / nfile;
+ r = ( il- kkp_hand_end ) % nfile;
+ ir = q*nfile + nfile-1-r + kkp_hand_end;
+ }
+ if ( k0l == k0r && k1l == k1r && il >= ir ) { continue; }
+
+ kkp[k0l][k1l][il] = kkp[k0r][k1r][ir];
+ }
+ }
+ }
+}
+
+
+double
+calc_penalty( void )
+{
+ uint64_t u64sum;
+ int i;
+
+ u64sum = 0;
+
+#define Foo(x) u64sum += (uint64_t)abs((int)x);
+ GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+
+ return (double)u64sum * FV_PENALTY;
+}
+
+
+void
+renovate_param( const param_t *pd )
+{
+ double *pv[14], *p;
+ double v[16];
+ unsigned int u32rand, u;
+ int i, j;
+
+ v[pawn] = pd->pawn; v[lance] = pd->lance;
+ v[knight] = pd->knight; v[silver] = pd->silver;
+ v[gold] = pd->gold; v[bishop] = pd->bishop;
+ v[rook] = pd->rook; v[pro_pawn] = pd->pro_pawn;
+ v[pro_lance] = pd->pro_lance; v[pro_knight] = pd->pro_knight;
+ v[pro_silver] = pd->pro_silver; v[horse] = pd->horse;
+ v[dragon] = pd->dragon; v[king] = FLT_MAX;
+
+ pv[ 0] = v + pawn; pv[ 1] = v + lance;
+ pv[ 2] = v + knight; pv[ 3] = v + silver;
+ pv[ 4] = v + gold; pv[ 5] = v + bishop;
+ pv[ 6] = v + rook; pv[ 7] = v + pro_pawn;
+ pv[ 8] = v + pro_lance; pv[ 9] = v + pro_knight;
+ pv[10] = v + pro_silver; pv[11] = v + horse;
+ pv[12] = v + dragon; pv[13] = v + king;
+
+ /* insertion sort */
+ for ( i = 13 - 2; i >= 0; i-- )
+ {
+ p = pv[i];
+ for ( j = i+1; *pv[j] < *p; j++ ) { pv[j-1] = pv[j]; }
+ pv[j-1] = p;
+ }
+
+ u32rand = rand32();
+ u = u32rand % 7U;
+ u32rand = u32rand / 7U;
+ p = pv[u+6]; pv[u+6] = pv[12]; pv[12] = p;
+ for ( i = 5; i > 0; i-- )
+ {
+ u = u32rand % (i+1);
+ u32rand = u32rand / (i+1);
+ p = pv[u]; pv[u] = pv[i]; pv[i] = p;
+
+ u = u32rand % (i+1);
+ u32rand = u32rand / (i+1);
+ p = pv[u+6]; pv[u+6] = pv[i+6]; pv[i+6] = p;
+ }
+
+ *pv[ 0] = *pv[ 1] = -2.0;
+ *pv[ 2] = *pv[ 3] = *pv[ 4] = -1.0;
+ *pv[ 5] = *pv[ 6] = *pv[ 7] = 0.0;
+ *pv[ 8] = *pv[ 9] = *pv[10] = 1.0;
+ *pv[11] = *pv[12] = 2.0;
+
+ rmt( v, pawn ); rmt( v, lance ); rmt( v, knight );
+ rmt( v, silver ); rmt( v, gold ); rmt( v, bishop );
+ rmt( v, rook ); rmt( v, pro_pawn ); rmt( v, pro_lance );
+ rmt( v, pro_knight ); rmt( v, pro_silver ); rmt( v, horse );
+ rmt( v, dragon );
+
+#define Foo(v) rparam( &v, pd->v );
+ GO_THROUGH_ALL_PARAMETERS_BY_FOO;
+#undef Foo
+
+ fv_sym();
+ set_derivative_param();
+ ehash_clear();
+}
+
+
+int
+out_param( void )
+{
+ size_t size;
+ FILE *pf;
+ int apc[17], apv[17];
+ int iret, i, j, pc, pv;
+
+ for ( i = 0; i < 17; i++ ) { apc[i] = i; apv[i] = INT_MAX; }
+ apv[pawn] = p_value_ex[15+pawn];
+ apv[lance] = p_value_ex[15+lance];
+ apv[knight] = p_value_ex[15+knight];
+ apv[silver] = p_value_ex[15+silver];
+ apv[gold] = p_value_ex[15+gold];
+ apv[bishop] = p_value_ex[15+bishop];
+ apv[rook] = p_value_ex[15+rook];
+ apv[pro_pawn] = p_value_ex[15+pro_pawn];
+ apv[pro_lance] = p_value_ex[15+pro_lance];
+ apv[pro_knight] = p_value_ex[15+pro_knight];
+ apv[pro_silver] = p_value_ex[15+pro_silver];
+ apv[horse] = p_value_ex[15+horse];
+ apv[dragon] = p_value_ex[15+dragon];
+
+ /* insertion sort */
+ for ( i = dragon-1; i >= 0; i-- )
+ {
+ pv = apv[i]; pc = apc[i];
+ for ( j = i+1; apv[j] < pv; j++ )
+ {
+ apv[j-1] = apv[j];
+ apc[j-1] = apc[j];
+ }
+ apv[j-1] = pv; apc[j-1] = pc;
+ }
+
+ pf = file_open( "param.h_", "w" );
+ if ( pf == NULL ) { return -2; }
+
+ for ( i = 0; i < 13; i++ )
+ {
+ fprintf( pf, "#define " );
+ switch ( apc[i] )
+ {
+ case pawn: fprintf( pf, "DPawn " ); break;
+ case lance: fprintf( pf, "DLance " ); break;
+ case knight: fprintf( pf, "DKnight " ); break;
+ case silver: fprintf( pf, "DSilver " ); break;
+ case gold: fprintf( pf, "DGold " ); break;
+ case bishop: fprintf( pf, "DBishop " ); break;
+ case rook: fprintf( pf, "DRook " ); break;
+ case pro_pawn: fprintf( pf, "DProPawn " ); break;
+ case pro_lance: fprintf( pf, "DProLance " ); break;
+ case pro_knight: fprintf( pf, "DProKnight" ); break;
+ case pro_silver: fprintf( pf, "DProSilver" ); break;
+ case horse: fprintf( pf, "DHorse " ); break;
+ case dragon: fprintf( pf, "DDragon " ); break;
+ }
+ fprintf( pf, " %4d /* %4d */\n", p_value[15+apc[i]], apv[i] );
+ }
+ fprintf( pf, "#define DKing 15000\n\n" );
+
+ iret = file_close( pf );
+ if ( iret < 0 ) { return -2; }
+
+ pf = file_open( "fv.bin", "wb" );
+ if ( pf == NULL ) { return -2; }
+
+ size = nsquare * pos_n;
+ if ( fwrite( pc_on_sq, sizeof(short), size, pf ) != size )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ size = nsquare * nsquare * kkp_end;
+ if ( fwrite( kkp, sizeof(short), size, pf ) != size )
+ {
+ str_error = str_io_error;
+ return -2;
+ }
+
+ return file_close( pf );
+}
+
+
+void
+inc_param( const tree_t * restrict ptree, param_t * restrict pd, double dinc )
+{
+ float f;
+ int anpiece[16], list0[52], list1[52];
+ int nlist, sq_bk, sq_wk, k0, k1, l0, l1, i, j;
+
+ f = (float)( dinc / (double)FV_SCALE );
+ nlist = make_list( ptree, list0, list1, anpiece, pd, f );
+ sq_bk = SQ_BKING;
+ sq_wk = Inv( SQ_WKING );
+
+ pd->pawn += dinc * (double)anpiece[pawn];
+ pd->lance += dinc * (double)anpiece[lance];
+ pd->knight += dinc * (double)anpiece[knight];
+ pd->silver += dinc * (double)anpiece[silver];
+ pd->gold += dinc * (double)anpiece[gold];
+ pd->bishop += dinc * (double)anpiece[bishop];
+ pd->rook += dinc * (double)anpiece[rook];
+ pd->pro_pawn += dinc * (double)anpiece[pro_pawn];
+ pd->pro_lance += dinc * (double)anpiece[pro_lance];
+ pd->pro_knight += dinc * (double)anpiece[pro_knight];
+ pd->pro_silver += dinc * (double)anpiece[pro_silver];
+ pd->horse += dinc * (double)anpiece[horse];
+ pd->dragon += dinc * (double)anpiece[dragon];
+
+ for ( i = 0; i < nlist; i++ )
+ {
+ k0 = list0[i];
+ k1 = list1[i];
+ for ( j = 0; j <= i; j++ )
+ {
+ l0 = list0[j];
+ l1 = list1[j];
+ assert( k0 >= l0 && k1 >= l1 );
+ pd->PcPcOnSq( sq_bk, k0, l0 ) += f;
+ pd->PcPcOnSq( sq_wk, k1, l1 ) -= f;
+ }
+ }
+}
+
+
+static int
+make_list( const tree_t * restrict ptree, int list0[52], int list1[52],
+ int anpiece[16], param_t * restrict pd, float f )
+{
+ bitboard_t bb;
+ int list2[34];
+ int nlist, sq, sq_bk0, sq_bk1, sq_wk0, sq_wk1, n2, i, itemp1, itemp2;
+
+ itemp1 = (int)I2HandPawn(HAND_B);
+ itemp2 = (int)I2HandPawn(HAND_W);
+ anpiece[pawn] = itemp1 - itemp2;
+
+ itemp1 = (int)I2HandLance(HAND_B);
+ itemp2 = (int)I2HandLance(HAND_W);
+ anpiece[lance] = itemp1 - itemp2;
+
+ itemp1 = (int)I2HandKnight(HAND_B);
+ itemp2 = (int)I2HandKnight(HAND_W);
+ anpiece[knight] = itemp1 - itemp2;
+
+ itemp1 = (int)I2HandSilver(HAND_B);
+ itemp2 = (int)I2HandSilver(HAND_W);
+ anpiece[silver] = itemp1 - itemp2;
+
+ itemp1 = (int)I2HandGold(HAND_B);
+ itemp2 = (int)I2HandGold(HAND_W);
+ anpiece[gold] = itemp1 - itemp2;
+
+ itemp1 = (int)I2HandBishop(HAND_B);
+ itemp2 = (int)I2HandBishop(HAND_W);
+ anpiece[bishop] = itemp1 - itemp2;
+
+ itemp1 = (int)I2HandRook(HAND_B);
+ itemp2 = (int)I2HandRook(HAND_W);
+ anpiece[rook] = itemp1 - itemp2;
+
+ anpiece[pro_pawn] = anpiece[pro_lance] = anpiece[pro_knight] = 0;
+ anpiece[pro_silver] = anpiece[horse] = anpiece[dragon] = 0;
+ nlist = 14;
+ sq_bk0 = SQ_BKING;
+ sq_wk0 = SQ_WKING;
+ sq_bk1 = Inv(SQ_WKING);
+ sq_wk1 = Inv(SQ_BKING);
+
+ list0[ 0] = f_hand_pawn + I2HandPawn(HAND_B);
+ list0[ 1] = e_hand_pawn + I2HandPawn(HAND_W);
+ list0[ 2] = f_hand_lance + I2HandLance(HAND_B);
+ list0[ 3] = e_hand_lance + I2HandLance(HAND_W);
+ list0[ 4] = f_hand_knight + I2HandKnight(HAND_B);
+ list0[ 5] = e_hand_knight + I2HandKnight(HAND_W);
+ list0[ 6] = f_hand_silver + I2HandSilver(HAND_B);
+ list0[ 7] = e_hand_silver + I2HandSilver(HAND_W);
+ list0[ 8] = f_hand_gold + I2HandGold(HAND_B);
+ list0[ 9] = e_hand_gold + I2HandGold(HAND_W);
+ list0[10] = f_hand_bishop + I2HandBishop(HAND_B);
+ list0[11] = e_hand_bishop + I2HandBishop(HAND_W);
+ list0[12] = f_hand_rook + I2HandRook(HAND_B);
+ list0[13] = e_hand_rook + I2HandRook(HAND_W);
+
+ list1[ 0] = f_hand_pawn + I2HandPawn(HAND_W);
+ list1[ 1] = e_hand_pawn + I2HandPawn(HAND_B);
+ list1[ 2] = f_hand_lance + I2HandLance(HAND_W);
+ list1[ 3] = e_hand_lance + I2HandLance(HAND_B);
+ list1[ 4] = f_hand_knight + I2HandKnight(HAND_W);
+ list1[ 5] = e_hand_knight + I2HandKnight(HAND_B);
+ list1[ 6] = f_hand_silver + I2HandSilver(HAND_W);
+ list1[ 7] = e_hand_silver + I2HandSilver(HAND_B);
+ list1[ 8] = f_hand_gold + I2HandGold(HAND_W);
+ list1[ 9] = e_hand_gold + I2HandGold(HAND_B);
+ list1[10] = f_hand_bishop + I2HandBishop(HAND_W);
+ list1[11] = e_hand_bishop + I2HandBishop(HAND_B);
+ list1[12] = f_hand_rook + I2HandRook(HAND_W);
+ list1[13] = e_hand_rook + I2HandRook(HAND_B);
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_hand_pawn +I2HandPawn(HAND_B) ] += f;
+ pd->kkp[sq_bk0][sq_wk0][kkp_hand_lance +I2HandLance(HAND_B) ] += f;
+ pd->kkp[sq_bk0][sq_wk0][kkp_hand_knight+I2HandKnight(HAND_B)] += f;
+ pd->kkp[sq_bk0][sq_wk0][kkp_hand_silver+I2HandSilver(HAND_B)] += f;
+ pd->kkp[sq_bk0][sq_wk0][kkp_hand_gold +I2HandGold(HAND_B) ] += f;
+ pd->kkp[sq_bk0][sq_wk0][kkp_hand_bishop+I2HandBishop(HAND_B)] += f;
+ pd->kkp[sq_bk0][sq_wk0][kkp_hand_rook +I2HandRook(HAND_B) ] += f;
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_hand_pawn +I2HandPawn(HAND_W) ] -= f;
+ pd->kkp[sq_bk1][sq_wk1][kkp_hand_lance +I2HandLance(HAND_W) ] -= f;
+ pd->kkp[sq_bk1][sq_wk1][kkp_hand_knight+I2HandKnight(HAND_W)] -= f;
+ pd->kkp[sq_bk1][sq_wk1][kkp_hand_silver+I2HandSilver(HAND_W)] -= f;
+ pd->kkp[sq_bk1][sq_wk1][kkp_hand_gold +I2HandGold(HAND_W) ] -= f;
+ pd->kkp[sq_bk1][sq_wk1][kkp_hand_bishop+I2HandBishop(HAND_W)] -= f;
+ pd->kkp[sq_bk1][sq_wk1][kkp_hand_rook +I2HandRook(HAND_W) ] -= f;
+
+ n2 = 0;
+ bb = BB_BPAWN;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_pawn+sq] += f;
+ anpiece[pawn] += 1;
+ list0[nlist] = f_pawn + sq;
+ list2[n2] = e_pawn + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WPAWN;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_pawn+Inv(sq)] -= f;
+ anpiece[pawn] -= 1;
+ list0[nlist] = e_pawn + sq;
+ list2[n2] = f_pawn + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+ n2 = 0;
+ bb = BB_BLANCE;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_lance+sq] += f;
+ anpiece[lance] += 1;
+ list0[nlist] = f_lance + sq;
+ list2[n2] = e_lance + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WLANCE;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_lance+Inv(sq)] -= f;
+ anpiece[lance] -= 1;
+ list0[nlist] = e_lance + sq;
+ list2[n2] = f_lance + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+ n2 = 0;
+ bb = BB_BKNIGHT;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_knight+sq] += f;
+ anpiece[knight] += 1;
+ list0[nlist] = f_knight + sq;
+ list2[n2] = e_knight + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WKNIGHT;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_knight+Inv(sq)] -= f;
+ anpiece[knight] -= 1;
+ list0[nlist] = e_knight + sq;
+ list2[n2] = f_knight + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+ n2 = 0;
+ bb = BB_BSILVER;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_silver+sq] += f;
+ anpiece[silver] += 1;
+ list0[nlist] = f_silver + sq;
+ list2[n2] = e_silver + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WSILVER;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_silver+Inv(sq)] -= f;
+ anpiece[silver] -= 1;
+ list0[nlist] = e_silver + sq;
+ list2[n2] = f_silver + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+ n2 = 0;
+ bb = BB_BTGOLD;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_gold+sq] += f;
+ anpiece[BOARD[sq]] += 1;
+ list0[nlist] = f_gold + sq;
+ list2[n2] = e_gold + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WTGOLD;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_gold+Inv(sq)] -= f;
+ anpiece[-BOARD[sq]] -= 1;
+ list0[nlist] = e_gold + sq;
+ list2[n2] = f_gold + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+ n2 = 0;
+ bb = BB_BBISHOP;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_bishop+sq] += f;
+ anpiece[bishop] += 1;
+ list0[nlist] = f_bishop + sq;
+ list2[n2] = e_bishop + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WBISHOP;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_bishop+Inv(sq)] -= f;
+ anpiece[bishop] -= 1;
+ list0[nlist] = e_bishop + sq;
+ list2[n2] = f_bishop + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+ n2 = 0;
+ bb = BB_BHORSE;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_horse+sq] += f;
+ anpiece[horse] += 1;
+ list0[nlist] = f_horse + sq;
+ list2[n2] = e_horse + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WHORSE;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_horse+Inv(sq)] -= f;
+ anpiece[horse] -= 1;
+ list0[nlist] = e_horse + sq;
+ list2[n2] = f_horse + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+ n2 = 0;
+ bb = BB_BROOK;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_rook+sq] += f;
+ anpiece[rook] += 1;
+ list0[nlist] = f_rook + sq;
+ list2[n2] = e_rook + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WROOK;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_rook+Inv(sq)] -= f;
+ anpiece[rook] -= 1;
+ list0[nlist] = e_rook + sq;
+ list2[n2] = f_rook + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+
+ n2 = 0;
+ bb = BB_BDRAGON;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk0][sq_wk0][kkp_dragon+sq] += f;
+ anpiece[dragon] += 1;
+ list0[nlist] = f_dragon + sq;
+ list2[n2] = e_dragon + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+
+ bb = BB_WDRAGON;
+ while ( BBToU(bb) ) {
+ sq = FirstOne( bb );
+ Xor( sq, bb );
+
+ pd->kkp[sq_bk1][sq_wk1][kkp_dragon+Inv(sq)] -= f;
+ anpiece[dragon] -= 1;
+ list0[nlist] = e_dragon + sq;
+ list2[n2] = f_dragon + Inv(sq);
+ nlist += 1;
+ n2 += 1;
+ }
+ for ( i = 0; i < n2; i++ ) { list1[nlist-i-1] = list2[i]; }
+
+ assert( nlist <= 52 );
+ return nlist;
+}
+
+
+static void
+rmt( const double avalue[16], int pc )
+{
+ int pc_v;
+
+ pc_v = (int)p_value[15+pc] + (int)avalue[pc];
+
+ if ( 0 < pc_v && pc_v <= SHRT_MAX ) { p_value[15+pc] = (short)pc_v; }
+ else {
+ out_warning( "A material value is out of bounce. (%s=%d)\n",
+ astr_table_piece[pc], pc_v );
+ }
+}
+
+
+static void
+rparam( short *pv, float dv )
+{
+ int v, istep;
+
+ istep = brand();
+ istep += brand();
+ v = *pv;
+
+ if ( v > 0 ) { dv -= (float)FV_PENALTY; }
+ else if ( v < 0 ) { dv += (float)FV_PENALTY; }
+
+ if ( dv >= 0.0 && v <= SHRT_MAX - istep ) { v += istep; }
+ else if ( dv <= 0.0 && v >= SHRT_MIN + istep ) { v -= istep; }
+ else { out_warning( "A fvcoef parameter is out of bounce.\n" ); }
+
+ *pv = (short)v;
+}
+
+
+static int
+brand( void )
+{
+ static unsigned int urand = 0;
+ static unsigned int uc = 31;
+ unsigned int uret;
+
+ if ( uc == 31 )
+ {
+ urand = rand32();
+ uc = 0;
+ }
+ else { uc += 1; }
+ uret = urand & 1U;
+ urand >>= 1;
+ return uret;
+}
+
+#endif /* MINIMUM */
--- /dev/null
+/*
+ BUG LIST
+
+ - detection of repetitions can be wrong due to collision of hash keys and
+ limitation of history table size.
+
+ - detection of mates fails if all of pseudo-legal evasions are perpetual
+ checks. Father more, inferior evasions, such as unpromotion of
+ bishop, rook, and lance at 8th rank, are not counted for the mate
+ detection.
+
+ - detection of perpetual checks fails if one of those inferior
+ evasions makes a position that occurred four times.
+*/
+/*
+ TODO:
+ - idirec && is_pinned_on_black_king();
+ - aifile and airank
+ - incheck at quies
+ - max legal moves
+ - tactical macro
+ - out_warning( "A node returns a value lower than mate." ); is obsolate.
+ - do_mate in hash
+ - pv store to hash
+ - no threat
+ - use IsDiscover macro
+ - change hash_store_pv()
+ - dek.c is obsolate.
+ - limit time ? ? num
+ - hash.bin
+ - SHARE to all transition table
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_WIN32)
+# include <fcntl.h>
+#endif
+#include "shogi.h"
+
+static int main_child( tree_t * restrict ptree );
+
+int CONV_CDECL
+#if defined(CSASHOGI)
+main( int argc, char *argv[] )
+#else
+main()
+#endif
+{
+ int iret;
+ tree_t * restrict ptree;
+
+#if defined(TLP)
+ ptree = tlp_atree_work;
+#else
+ ptree = &tree;
+#endif
+
+#if defined(CSASHOGI) && defined(_WIN32)
+ FreeConsole();
+ if ( argc != 2 || strcmp( argv[1], "csa_shogi" ) )
+ {
+ MessageBox( NULL,
+ "The executable image is not intended\x0d"
+ "as an independent program file.\x0d"
+ "Execute CSA.EXE instead.",
+ str_myname, MB_OK | MB_ICONINFORMATION );
+ return EXIT_FAILURE;
+ }
+#endif
+
+ if ( ini( ptree ) < 0 )
+ {
+ out_error( "%s", str_error );
+ return EXIT_SUCCESS;
+ }
+
+ for ( ;; )
+ {
+ iret = main_child( ptree );
+ if ( iret == -1 )
+ {
+ out_error( "%s", str_error );
+ ShutdownClient;
+ break;
+ }
+ else if ( iret == -2 )
+ {
+ out_warning( "%s", str_error );
+ ShutdownClient;
+ continue;
+ }
+ else if ( iret == -3 ) { break; }
+ }
+
+ if ( fin() < 0 ) { out_error( "%s", str_error ); }
+
+ return EXIT_SUCCESS;
+}
+
+
+static int
+main_child( tree_t * restrict ptree )
+{
+ int iret;
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame && ( game_status & mask_game_end ) )
+ {
+ TlpEnd();
+ if ( dek_next_game( ptree ) < 0 )
+ {
+ out_error( "%s", str_error );
+ return -3;
+ }
+ }
+#endif
+
+ /* ponder a move */
+ ponder_move = 0;
+ iret = ponder( ptree );
+ if ( iret < 0 ) { return iret; }
+ else if ( game_status & flag_quit ) { return -3; }
+
+ /* move prediction succeeded, pondering finished,
+ and computer made a move. */
+ else if ( iret == 2 ) { return 1; }
+
+ /* move prediction failed, pondering aborted,
+ and we have opponent's move in input buffer. */
+ else if ( ponder_move == MOVE_PONDER_FAILED )
+ {
+ }
+
+ /* pondering is interrupted or ended.
+ do nothing until we get next input line. */
+ else {
+ TlpEnd();
+ show_prompt();
+ }
+
+
+ iret = next_cmdline( 1 );
+ if ( iret < 0 ) { return iret; }
+ else if ( game_status & flag_quit ) { return -3; }
+
+
+ iret = procedure( ptree );
+ if ( iret < 0 ) { return iret; }
+ else if ( game_status & flag_quit ) { return -3; }
+
+ return 1;
+}
--- /dev/null
+#include <assert.h>
+#include <string.h>
+#include "shogi.h"
+
+#define DropB( PIECE, piece ) Xor( to, BB_B ## PIECE ); \
+ HASH_KEY ^= ( b_ ## piece ## _rand )[to]; \
+ HAND_B -= flag_hand_ ## piece; \
+ BOARD[to] = piece
+
+#define DropW( PIECE, piece ) Xor( to, BB_W ## PIECE ); \
+ HASH_KEY ^= ( w_ ## piece ## _rand )[to]; \
+ HAND_W -= flag_hand_ ## piece; \
+ BOARD[to] = - piece
+
+#define CapB( PIECE, piece, pro_piece ) \
+ Xor( to, BB_B ## PIECE ); \
+ HASH_KEY ^= ( b_ ## pro_piece ## _rand )[to]; \
+ HAND_W += flag_hand_ ## piece; \
+ MATERIAL -= MT_CAP_ ## PIECE
+
+#define CapW( PIECE, piece, pro_piece ) \
+ Xor( to, BB_W ## PIECE ); \
+ HASH_KEY ^= ( w_ ## pro_piece ## _rand )[to]; \
+ HAND_B += flag_hand_ ## piece; \
+ MATERIAL += MT_CAP_ ## PIECE
+
+#define NocapProB( PIECE, PRO_PIECE, piece, pro_piece ) \
+ Xor( from, BB_B ## PIECE ); \
+ Xor( to, BB_B ## PRO_PIECE ); \
+ HASH_KEY ^= ( b_ ## pro_piece ## _rand )[to] \
+ ^ ( b_ ## piece ## _rand )[from]; \
+ MATERIAL += MT_PRO_ ## PIECE; \
+ BOARD[to] = pro_piece
+
+#define NocapProW( PIECE, PRO_PIECE, piece, pro_piece ) \
+ Xor( from, BB_W ## PIECE ); \
+ Xor( to, BB_W ## PRO_PIECE ); \
+ HASH_KEY ^= ( w_ ## pro_piece ## _rand )[to] \
+ ^ ( w_ ## piece ## _rand )[from]; \
+ MATERIAL -= MT_PRO_ ## PIECE; \
+ BOARD[to] = - pro_piece
+
+#define NocapNoproB( PIECE, piece ) \
+ SetClear( BB_B ## PIECE ); \
+ HASH_KEY ^= ( b_ ## piece ## _rand )[to] \
+ ^ ( b_ ## piece ## _rand )[from]; \
+ BOARD[to] = piece
+
+#define NocapNoproW( PIECE, piece ) \
+ SetClear( BB_W ## PIECE ); \
+ HASH_KEY ^= ( w_ ## piece ## _rand )[to] \
+ ^ ( w_ ## piece ## _rand )[from]; \
+ BOARD[to] = - piece
+
+
+void
+make_move_b( tree_t * restrict ptree, unsigned int move, int ply )
+{
+ const int from = (int)I2From(move);
+ const int to = (int)I2To(move);
+ const int nrep = root_nrep + ply - 1;
+
+ assert( UToCap(move) != king );
+ assert( move );
+ assert( is_move_valid( ptree, move, black ) );
+
+ ptree->rep_board_list[nrep] = HASH_KEY;
+ ptree->rep_hand_list[nrep] = HAND_B;
+ ptree->save_material[ply] = (short)MATERIAL;
+ ptree->stand_pat[ply+1] = score_bound;
+
+ if ( from >= nsquare )
+ {
+ switch ( From2Drop(from) )
+ {
+ case pawn: Xor( to-nfile, BB_BPAWN_ATK );
+ DropB( PAWN, pawn ); break;
+ case lance: DropB( LANCE, lance ); break;
+ case knight: DropB( KNIGHT, knight ); break;
+ case silver: DropB( SILVER, silver ); break;
+ case gold: DropB( GOLD, gold );
+ Xor( to, BB_BTGOLD ); break;
+ case bishop: DropB( BISHOP, bishop );
+ Xor( to, BB_B_BH ); break;
+ default: assert( From2Drop(from) == rook );
+ DropB( ROOK, rook );
+ Xor( to, BB_B_RD ); break;
+ }
+ Xor( to, BB_BOCCUPY );
+ XorFile( to, OCCUPIED_FILE );
+ XorDiag2( to, OCCUPIED_DIAG2 );
+ XorDiag1( to, OCCUPIED_DIAG1 );
+ }
+ else {
+ const int ipiece_move = (int)I2PieceMove(move);
+ const int ipiece_cap = (int)UToCap(move);
+ const int is_promote = (int)I2IsPromote(move);
+ bitboard_t bb_set_clear;
+
+ BBOr( bb_set_clear, abb_mask[from], abb_mask[to] );
+ SetClear( BB_BOCCUPY );
+ BOARD[from] = empty;
+
+ if ( is_promote ) switch( ipiece_move )
+ {
+ case pawn: Xor( to, BB_BPAWN_ATK );
+ Xor( to, BB_BTGOLD );
+ NocapProB( PAWN, PRO_PAWN, pawn, pro_pawn ); break;
+ case lance: Xor( to, BB_BTGOLD );
+ NocapProB( LANCE, PRO_LANCE, lance, pro_lance ); break;
+ case knight: Xor( to, BB_BTGOLD );
+ NocapProB( KNIGHT, PRO_KNIGHT, knight, pro_knight ); break;
+ case silver: Xor( to, BB_BTGOLD );
+ NocapProB( SILVER, PRO_SILVER, silver, pro_silver ); break;
+ case bishop: Xor( to, BB_B_HDK );
+ SetClear( BB_B_BH );
+ NocapProB( BISHOP, HORSE, bishop, horse ); break;
+ default: assert( ipiece_move == rook );
+ Xor( to, BB_B_HDK );
+ SetClear( BB_B_RD );
+ NocapProB( ROOK, DRAGON, rook, dragon ); break;
+ }
+ else switch ( ipiece_move )
+ {
+ case pawn: Xor( to-nfile, BB_BPAWN_ATK );
+ Xor( to, BB_BPAWN_ATK );
+ NocapNoproB( PAWN, pawn); break;
+ case lance: NocapNoproB( LANCE, lance); break;
+ case knight: NocapNoproB( KNIGHT, knight); break;
+ case silver: NocapNoproB( SILVER, silver); break;
+ case gold: NocapNoproB( GOLD, gold);
+ SetClear( BB_BTGOLD ); break;
+ case bishop: SetClear( BB_B_BH );
+ NocapNoproB( BISHOP, bishop); break;
+ case rook: NocapNoproB( ROOK, rook);
+ SetClear( BB_B_RD ); break;
+ case king: HASH_KEY ^= b_king_rand[to] ^ b_king_rand[from];
+ SetClear( BB_B_HDK );
+ BOARD[to] = king;
+ SQ_BKING = (char)to; break;
+ case pro_pawn: NocapNoproB( PRO_PAWN, pro_pawn );
+ SetClear( BB_BTGOLD ); break;
+ case pro_lance: NocapNoproB( PRO_LANCE, pro_lance );
+ SetClear( BB_BTGOLD ); break;
+ case pro_knight: NocapNoproB( PRO_KNIGHT, pro_knight );
+ SetClear( BB_BTGOLD ); break;
+ case pro_silver: NocapNoproB( PRO_SILVER, pro_silver );
+ SetClear( BB_BTGOLD ); break;
+ case horse: NocapNoproB( HORSE, horse );
+ SetClear( BB_B_HDK );
+ SetClear( BB_B_BH ); break;
+ default: assert( ipiece_move == dragon );
+ NocapNoproB( DRAGON, dragon );
+ SetClear( BB_B_HDK );
+ SetClear( BB_B_RD ); break;
+ }
+
+ if ( ipiece_cap )
+ {
+ switch( ipiece_cap )
+ {
+ case pawn: CapW( PAWN, pawn, pawn );
+ Xor( to+nfile, BB_WPAWN_ATK ); break;
+ case lance: CapW( LANCE, lance, lance ); break;
+ case knight: CapW( KNIGHT, knight, knight ); break;
+ case silver: CapW( SILVER, silver, silver ); break;
+ case gold: CapW( GOLD, gold, gold );
+ Xor( to, BB_WTGOLD ); break;
+ case bishop: CapW( BISHOP, bishop, bishop );
+ Xor( to, BB_W_BH ); break;
+ case rook: CapW( ROOK, rook, rook);
+ Xor( to, BB_W_RD ); break;
+ case pro_pawn: CapW( PRO_PAWN, pawn, pro_pawn );
+ Xor( to, BB_WTGOLD ); break;
+ case pro_lance: CapW( PRO_LANCE, lance, pro_lance );
+ Xor( to, BB_WTGOLD ); break;
+ case pro_knight: CapW( PRO_KNIGHT, knight, pro_knight );
+ Xor( to, BB_WTGOLD ); break;
+ case pro_silver: CapW( PRO_SILVER, silver, pro_silver );
+ Xor( to, BB_WTGOLD ); break;
+ case horse: CapW( HORSE, bishop, horse );
+ Xor( to, BB_W_HDK );
+ Xor( to, BB_W_BH ); break;
+ default: assert( ipiece_cap == dragon );
+ CapW( DRAGON, rook, dragon );
+ Xor( to, BB_W_HDK );
+ Xor( to, BB_W_RD ); break;
+ }
+ Xor( to, BB_WOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ }
+ else {
+ SetClearFile( from, to, OCCUPIED_FILE );
+ SetClearDiag1( from, to, OCCUPIED_DIAG1 );
+ SetClearDiag2( from, to, OCCUPIED_DIAG2 );
+ }
+ }
+
+ assert( exam_bb( ptree ) );
+}
+
+
+void
+make_move_w( tree_t * restrict ptree, unsigned int move, int ply )
+{
+ const int from = (int)I2From(move);
+ const int to = (int)I2To(move);
+ const int nrep = root_nrep + ply - 1;
+
+ assert( UToCap(move) != king );
+ assert( move );
+ assert( is_move_valid( ptree, move, white ) );
+
+ ptree->rep_board_list[nrep] = HASH_KEY;
+ ptree->rep_hand_list[nrep] = HAND_B;
+ ptree->save_material[ply] = (short)MATERIAL;
+ ptree->stand_pat[ply+1] = score_bound;
+
+ if ( from >= nsquare )
+ {
+ switch( From2Drop(from) )
+ {
+ case pawn: Xor( to+nfile, BB_WPAWN_ATK );
+ DropW( PAWN, pawn ); break;
+ case lance: DropW( LANCE, lance ); break;
+ case knight: DropW( KNIGHT, knight ); break;
+ case silver: DropW( SILVER, silver ); break;
+ case gold: DropW( GOLD, gold );
+ Xor( to, BB_WTGOLD ); break;
+ case bishop: DropW( BISHOP, bishop );
+ Xor( to, BB_W_BH ); break;
+ default: DropW( ROOK, rook );
+ Xor( to, BB_W_RD ); break;
+ }
+ Xor( to, BB_WOCCUPY );
+ XorFile( to, OCCUPIED_FILE );
+ XorDiag2( to, OCCUPIED_DIAG2 );
+ XorDiag1( to, OCCUPIED_DIAG1 );
+ }
+ else {
+ const int ipiece_move = (int)I2PieceMove(move);
+ const int ipiece_cap = (int)UToCap(move);
+ const int is_promote = (int)I2IsPromote(move);
+ bitboard_t bb_set_clear;
+
+ BBOr( bb_set_clear, abb_mask[from], abb_mask[to] );
+ SetClear( BB_WOCCUPY );
+ BOARD[from] = empty;
+
+ if ( is_promote) switch( ipiece_move )
+ {
+ case pawn: NocapProW( PAWN, PRO_PAWN, pawn, pro_pawn );
+ Xor( to, BB_WPAWN_ATK );
+ Xor( to, BB_WTGOLD ); break;
+ case lance: NocapProW( LANCE, PRO_LANCE, lance, pro_lance );
+ Xor( to, BB_WTGOLD ); break;
+ case knight: NocapProW( KNIGHT, PRO_KNIGHT, knight, pro_knight );
+ Xor( to, BB_WTGOLD ); break;
+ case silver: NocapProW( SILVER, PRO_SILVER, silver, pro_silver );
+ Xor( to, BB_WTGOLD ); break;
+ case bishop: NocapProW( BISHOP, HORSE, bishop, horse );
+ Xor( to, BB_W_HDK );
+ SetClear( BB_W_BH ); break;
+ default: NocapProW( ROOK, DRAGON, rook, dragon);
+ Xor( to, BB_W_HDK );
+ SetClear( BB_W_RD ); break;
+ }
+ else switch ( ipiece_move )
+ {
+ case pawn: NocapNoproW( PAWN, pawn );
+ Xor( to+nfile, BB_WPAWN_ATK );
+ Xor( to, BB_WPAWN_ATK ); break;
+ case lance: NocapNoproW( LANCE, lance); break;
+ case knight: NocapNoproW( KNIGHT, knight); break;
+ case silver: NocapNoproW( SILVER, silver); break;
+ case gold: NocapNoproW( GOLD, gold);
+ SetClear( BB_WTGOLD ); break;
+ case bishop: NocapNoproW( BISHOP, bishop);
+ SetClear( BB_W_BH ); break;
+ case rook: NocapNoproW( ROOK, rook);
+ SetClear( BB_W_RD ); break;
+ case king: HASH_KEY ^= w_king_rand[to] ^ w_king_rand[from];
+ BOARD[to] = - king;
+ SQ_WKING = (char)to;
+ SetClear( BB_W_HDK ); break;
+ case pro_pawn: NocapNoproW( PRO_PAWN, pro_pawn);
+ SetClear( BB_WTGOLD ); break;
+ case pro_lance: NocapNoproW( PRO_LANCE, pro_lance);
+ SetClear( BB_WTGOLD ); break;
+ case pro_knight: NocapNoproW( PRO_KNIGHT, pro_knight);
+ SetClear( BB_WTGOLD ); break;
+ case pro_silver: NocapNoproW( PRO_SILVER, pro_silver);
+ SetClear( BB_WTGOLD ); break;
+ case horse: NocapNoproW( HORSE, horse );
+ SetClear( BB_W_HDK );
+ SetClear( BB_W_BH ); break;
+ default: NocapNoproW( DRAGON, dragon );
+ SetClear( BB_W_HDK );
+ SetClear( BB_W_RD ); break;
+ }
+
+ if ( ipiece_cap )
+ {
+ switch( ipiece_cap )
+ {
+ case pawn: CapB( PAWN, pawn, pawn );
+ Xor( to-nfile, BB_BPAWN_ATK ); break;
+ case lance: CapB( LANCE, lance, lance ); break;
+ case knight: CapB( KNIGHT, knight, knight ); break;
+ case silver: CapB( SILVER, silver, silver ); break;
+ case gold: CapB( GOLD, gold, gold );
+ Xor( to, BB_BTGOLD ); break;
+ case bishop: CapB( BISHOP, bishop, bishop );
+ Xor( to, BB_B_BH ); break;
+ case rook: CapB( ROOK, rook, rook );
+ Xor( to, BB_B_RD ); break;
+ case pro_pawn: CapB( PRO_PAWN, pawn, pro_pawn );
+ Xor( to, BB_BTGOLD ); break;
+ case pro_lance: CapB( PRO_LANCE, lance, pro_lance );
+ Xor( to, BB_BTGOLD ); break;
+ case pro_knight: CapB( PRO_KNIGHT, knight, pro_knight );
+ Xor( to, BB_BTGOLD ); break;
+ case pro_silver: CapB( PRO_SILVER, silver, pro_silver );
+ Xor( to, BB_BTGOLD ); break;
+ case horse: CapB( HORSE, bishop, horse );
+ Xor( to, BB_B_HDK );
+ Xor( to, BB_B_BH ); break;
+ default: CapB( DRAGON, rook, dragon );
+ Xor( to, BB_B_HDK );
+ Xor( to, BB_B_RD ); break;
+ }
+ Xor( to, BB_BOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ }
+ else {
+ SetClearFile( from, to, OCCUPIED_FILE );
+ SetClearDiag1( from, to, OCCUPIED_DIAG1 );
+ SetClearDiag2( from, to, OCCUPIED_DIAG2 );
+ }
+ }
+
+ assert( exam_bb( ptree ) );
+}
+
+#undef DropB
+#undef DropW
+#undef CapB
+#undef CapW
+#undef NocapProB
+#undef NocapProW
+#undef NocapNoproB
+#undef NocapNoproW
+
+/*
+ * flag_detect_hang
+ * flag_rep
+ * flag_time
+ * flag_nomake_move
+ * flag_history
+ * flag_rejections
+ */
+int
+make_move_root( tree_t * restrict ptree, unsigned int move, int flag )
+{
+ int check, drawn, iret, i, n;
+
+ ptree->save_material[0] = (short)MATERIAL;
+ MakeMove( root_turn, move, 1 );
+
+ /* detect hang-king */
+ if ( ( flag & flag_detect_hang ) && InCheck(root_turn) )
+ {
+ str_error = str_king_hang;
+ UnMakeMove( root_turn, move, 1 );
+ return -2;
+ }
+
+ drawn = 0;
+ check = InCheck( Flip(root_turn) );
+ ptree->move_last[1] = ptree->move_last[0];
+ if ( check )
+ {
+ ptree->nsuc_check[2] = (unsigned char)( ptree->nsuc_check[0] + 1U );
+ }
+ else { ptree->nsuc_check[2] = 0; }
+
+ /* detect repetitions */
+ if ( flag & flag_rep )
+ {
+ switch ( detect_repetition( ptree, 2, Flip(root_turn), 3 ) )
+ {
+ case perpetual_check:
+ str_error = str_perpet_check;
+ UnMakeMove( root_turn, move, 1 );
+ return -2;
+
+ case four_fold_rep:
+ drawn = 1;
+ break;
+ }
+ }
+
+ /* return, since all of rule-checks were done */
+ if ( flag & flag_nomake_move )
+ {
+ UnMakeMove( root_turn, move, 1 );
+ return drawn ? 2 : 1;
+ }
+
+ if ( drawn ) { game_status |= flag_drawn; }
+
+ /* renovate time */
+ if ( flag & flag_time )
+ {
+ iret = renovate_time( root_turn );
+ if ( iret < 0 ) { return iret; }
+ }
+
+ root_turn = Flip( root_turn );
+
+ /* detect checkmate */
+ if ( check && is_mate( ptree, 1 ) ) { game_status |= flag_mated; }
+
+ /* save history */
+ if ( flag & flag_history )
+ {
+ /* save history for book learning */
+ if ( record_game.moves < HASH_REG_HIST_LEN )
+ {
+ history_book_learn[ record_game.moves ].move_played = move;
+ history_book_learn[ record_game.moves ].hand_played
+ = ptree->rep_hand_list[ root_nrep ];
+ history_book_learn[ record_game.moves ].key_played
+ = (unsigned int)ptree->rep_board_list[ root_nrep ];
+ }
+
+ out_CSA( ptree, &record_game, move );
+ }
+
+ /* add rejections */
+ if ( flag & flag_rejections ) { add_rejections_root( ptree, move ); }
+
+ /* renew repetition table */
+ n = root_nrep;
+ if ( n >= REP_HIST_LEN - PLY_MAX -1 )
+ {
+ for ( i = 0; i < n; i++ )
+ {
+ ptree->rep_board_list[i] = ptree->rep_board_list[i+1];
+ ptree->rep_hand_list[i] = ptree->rep_hand_list[i+1];
+ }
+ }
+ else { root_nrep++; }
+
+ ptree->nsuc_check[PLY_MAX] = ptree->nsuc_check[0];
+ ptree->nsuc_check[0] = ptree->nsuc_check[1];
+ ptree->nsuc_check[1] = ptree->nsuc_check[2];
+
+ /* renovate pv */
+ last_root_value_save = last_root_value;
+ last_pv_save = last_pv;
+ if ( last_pv.a[1] == move && last_pv.length >= 2 )
+ {
+ if ( last_pv.depth )
+ {
+#if PLY_INC == EXT_CHECK
+ if ( ! check )
+#endif
+ last_pv.depth--;
+ }
+ last_pv.length--;
+ memmove( &(last_pv.a[1]), &(last_pv.a[2]),
+ last_pv.length * sizeof( unsigned int ) );
+ }
+ else {
+ last_pv.a[0] = 0;
+ last_pv.a[1] = 0;
+ last_pv.depth = 0;
+ last_pv.length = 0;
+ last_root_value = 0;
+ }
+
+ return 1;
+}
+
+
+void
+unmake_move_root( tree_t * restrict ptree, unsigned int move )
+{
+ last_root_value = last_root_value_save;
+ last_pv = last_pv_save;
+
+ ptree->nsuc_check[1] = ptree->nsuc_check[0];
+ ptree->nsuc_check[0] = ptree->nsuc_check[PLY_MAX];
+
+ root_nrep -= 1;
+ game_status &= ~( flag_drawn | flag_mated );
+ root_turn = Flip(root_turn);
+
+ ptree->save_material[1] = ptree->save_material[0];
+ UnMakeMove( root_turn, move, 1 );
+
+ sub_rejections_root( ptree, move );
+}
--- /dev/null
+#include <assert.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+#define DebugOut { static int count = 0; \
+ if ( count++ < 16 ) { out_CSA_posi( ptree, stdout, 0 ); } }
+
+static int can_w_king_escape( tree_t * restrict ptree, int to, bitboard_t bb );
+static int can_b_king_escape( tree_t * restrict ptree, int to, bitboard_t bb );
+static int can_w_piece_capture( const tree_t * restrict ptree, int to );
+static int can_b_piece_capture( const tree_t * restrict ptree, int to );
+
+
+unsigned int
+is_b_mate_in_1ply( tree_t * restrict ptree )
+{
+ bitboard_t bb, bb_temp, bb_check, bb_check_pro, bb_attacks, bb_drop, bb_move;
+ unsigned int ubb;
+ int to, from, idirec;
+
+ assert( ! is_black_attacked( ptree, SQ_BKING ) );
+
+ /* Drops */
+ BBOr( bb_drop, BB_BOCCUPY, BB_WOCCUPY );
+ BBNot( bb_drop, bb_drop );
+
+ if ( IsHandRook(HAND_B) ) {
+
+ BBAnd( bb, abb_w_gold_attacks[SQ_WKING],
+ abb_b_gold_attacks[SQ_WKING] );
+ BBAnd( bb, bb, bb_drop );
+ while( BBToU(bb) )
+ {
+ to = FirstOne( bb );
+ Xor( to, bb );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(rook);
+ }
+
+ } else if ( IsHandLance(HAND_B) && SQ_WKING <= I2 ) {
+
+ to = SQ_WKING+nfile;
+ if ( ! BOARD[to] && is_white_attacked( ptree, to ) )
+ {
+ bb_attacks = abb_file_attacks[to][0];
+ if ( ! can_w_king_escape( ptree, to, bb_attacks )
+ && ! can_w_piece_capture( ptree, to ) )
+ {
+ return To2Move(to) | Drop2Move(lance);
+ }
+ }
+ }
+
+ if ( IsHandBishop(HAND_B) ) {
+
+ BBAnd( bb, abb_w_silver_attacks[SQ_WKING],
+ abb_b_silver_attacks[SQ_WKING] );
+ BBAnd( bb, bb, bb_drop );
+ while( BBToU(bb) )
+ {
+ to = FirstOne( bb );
+ Xor( to, bb );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+ abb_bishop_attacks_rl45[to][0] );
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(bishop);
+ }
+ }
+
+ if ( IsHandGold(HAND_B) ) {
+
+ if ( IsHandRook(HAND_B) )
+ {
+ BBAnd( bb, abb_b_gold_attacks[SQ_WKING],
+ abb_b_silver_attacks[SQ_WKING] );
+ BBNot( bb, bb );
+ BBAnd( bb, bb, bb_drop );
+ BBAnd( bb, bb, abb_w_gold_attacks[SQ_WKING] );
+ }
+ else { BBAnd( bb, bb_drop, abb_w_gold_attacks[SQ_WKING] ); }
+
+ while ( BBToU(bb) )
+ {
+ to = FirstOne( bb );
+ Xor( to, bb );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_gold_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(gold);
+ }
+ }
+
+ if ( IsHandSilver(HAND_B) ) {
+
+ if ( IsHandGold(HAND_B) )
+ {
+ if ( IsHandBishop(HAND_B) ) { goto b_silver_drop_end; }
+ BBNot( bb, abb_w_gold_attacks[SQ_WKING] );
+ BBAnd( bb, bb, abb_w_silver_attacks[SQ_WKING] );
+ BBAnd( bb, bb, bb_drop );
+ }
+ else {
+ BBAnd( bb, bb_drop, abb_w_silver_attacks[SQ_WKING] );
+ if ( IsHandBishop(HAND_B) )
+ {
+ BBAnd( bb, bb, abb_w_gold_attacks[SQ_WKING] );
+ }
+ }
+
+ while ( BBToU(bb) )
+ {
+ to = FirstOne( bb );
+ Xor( to, bb );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_silver_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(silver);
+ }
+ }
+ b_silver_drop_end:
+
+ if ( IsHandKnight(HAND_B) ) {
+
+ BBAnd( bb, bb_drop, abb_w_knight_attacks[SQ_WKING] );
+ while ( BBToU(bb) )
+ {
+ to = FirstOne( bb );
+ Xor( to, bb );
+
+ BBIni( bb_attacks );
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(knight);
+ }
+ }
+
+ /* Moves */
+ BBNot( bb_move, BB_BOCCUPY );
+
+ bb = BB_BDRAGON;
+ while ( BBToU(bb) ) {
+ from = FirstOne( bb );
+ Xor( from, bb );
+
+ AttackDragon( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ BBAnd( bb_check, bb_check, abb_king_attacks[SQ_WKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ Xor( from, BB_B_HDK );
+ Xor( from, BB_B_RD );
+ Xor( from, BB_BOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = FirstOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ if ( (int)adirec[SQ_WKING][to] & flag_cross )
+ {
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+ }
+ else { AttackDragon( bb_attacks, to ); }
+
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_B_RD );
+ Xor( from, BB_B_HDK );
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(dragon) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_B_RD );
+ Xor( from, BB_B_HDK );
+ }
+
+ bb.p[0] = BB_BROOK.p[0];
+ while ( bb.p[0] ) {
+ from = last_one0( bb.p[0] );
+ bb.p[0] ^= abb_mask[from].p[0];
+
+ AttackRook( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ BBAnd( bb_check, bb_check, abb_king_attacks[SQ_WKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ BB_B_RD.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = FirstOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ if ( (int)adirec[SQ_WKING][to] & flag_cross )
+ {
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+ }
+ else { AttackDragon( bb_attacks, to ); }
+
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_B_RD.p[0] ^= abb_mask[from].p[0];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(-BOARD[to]) | Piece2Move(rook) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_B_RD.p[0] ^= abb_mask[from].p[0];
+ }
+
+ bb.p[1] = BB_BROOK.p[1];
+ bb.p[2] = BB_BROOK.p[2];
+ while ( bb.p[1] | bb.p[2] ) {
+ from = first_one12( bb.p[1], bb.p[2] );
+ bb.p[1] ^= abb_mask[from].p[1];
+ bb.p[2] ^= abb_mask[from].p[2];
+
+ AttackRook( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ bb_check.p[0] &= abb_king_attacks[SQ_WKING].p[0];
+ bb_check.p[1] &= abb_b_gold_attacks[SQ_WKING].p[1];
+ bb_check.p[2] &= abb_b_gold_attacks[SQ_WKING].p[2];
+ bb_check.p[1] &= abb_w_gold_attacks[SQ_WKING].p[1];
+ bb_check.p[2] &= abb_w_gold_attacks[SQ_WKING].p[2];
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ BB_B_RD.p[1] ^= abb_mask[from].p[1];
+ BB_B_RD.p[2] ^= abb_mask[from].p[2];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = FirstOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ if ( to <= I7 ) {
+ if ( (int)adirec[SQ_WKING][to] & flag_cross )
+ {
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ bb_attacks.p[0] |= abb_king_attacks[to].p[0];
+ bb_attacks.p[1] |= abb_king_attacks[to].p[1];
+ }
+ else { AttackDragon( bb_attacks, to ); }
+
+ } else {
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ }
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_B_RD.p[1] ^= abb_mask[from].p[1];
+ BB_B_RD.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from)
+ | ( (to < A6) ? FLAG_PROMO : 0 )
+ | Cap2Move(-BOARD[to]) | Piece2Move(rook) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_B_RD.p[1] ^= abb_mask[from].p[1];
+ BB_B_RD.p[2] ^= abb_mask[from].p[2];
+ }
+
+ bb = BB_BHORSE;
+ while ( BBToU(bb) ) {
+ from = FirstOne( bb );
+ Xor( from, bb );
+
+ AttackHorse( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ BBAnd( bb_check, bb_check, abb_king_attacks[SQ_WKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ Xor( from, BB_B_HDK );
+ Xor( from, BB_B_BH );
+ Xor( from, BB_BOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = FirstOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+ abb_bishop_attacks_rl45[to][0] );
+ BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_B_BH );
+ Xor( from, BB_B_HDK );
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(horse) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_B_BH );
+ Xor( from, BB_B_HDK );
+ }
+
+ bb.p[0] = BB_BBISHOP.p[0];
+ while ( bb.p[0] ) {
+ from = last_one0( bb.p[0] );
+ bb.p[0] ^= abb_mask[from].p[0];
+
+ AttackBishop( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ BBAnd( bb_check, bb_check, abb_king_attacks[SQ_WKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ BB_B_BH.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = FirstOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+ abb_bishop_attacks_rl45[to][0] );
+ BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_B_BH.p[0] ^= abb_mask[from].p[0];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(-BOARD[to]) | Piece2Move(bishop) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_B_BH.p[0] ^= abb_mask[from].p[0];
+ }
+
+ bb.p[1] = BB_BBISHOP.p[1];
+ bb.p[2] = BB_BBISHOP.p[2];
+ while ( bb.p[1] | bb.p[2] ) {
+ from = first_one12( bb.p[1], bb.p[2] );
+ bb.p[1] ^= abb_mask[from].p[1];
+ bb.p[2] ^= abb_mask[from].p[2];
+
+ AttackBishop( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ bb_check.p[0] &= abb_king_attacks[SQ_WKING].p[0];
+ bb_check.p[1] &= abb_b_silver_attacks[SQ_WKING].p[1];
+ bb_check.p[2] &= abb_b_silver_attacks[SQ_WKING].p[2];
+ bb_check.p[1] &= abb_w_silver_attacks[SQ_WKING].p[1];
+ bb_check.p[2] &= abb_w_silver_attacks[SQ_WKING].p[2];
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ BB_B_BH.p[1] ^= abb_mask[from].p[1];
+ BB_B_BH.p[2] ^= abb_mask[from].p[2];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = FirstOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+ abb_bishop_attacks_rl45[to][0] );
+ if ( to <= I7 ) {
+ bb_attacks.p[0] |= abb_king_attacks[to].p[0];
+ bb_attacks.p[1] |= abb_king_attacks[to].p[1];
+ }
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_B_BH.p[1] ^= abb_mask[from].p[1];
+ BB_B_BH.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from)
+ | ( (to < A6) ? FLAG_PROMO : 0 )
+ | Cap2Move(-BOARD[to]) | Piece2Move(bishop) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_B_BH.p[1] ^= abb_mask[from].p[1];
+ BB_B_BH.p[2] ^= abb_mask[from].p[2];
+ }
+
+ BBAnd( bb, BB_BTGOLD, b_chk_tbl[SQ_WKING].gold );
+ while ( BBToU(bb) ) {
+ from = FirstOne( bb );
+ Xor( from, bb );
+
+ BBAnd( bb_check, bb_move, abb_b_gold_attacks[from] );
+ BBAnd( bb_check, bb_check, abb_w_gold_attacks[SQ_WKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ Xor( from, BB_BTGOLD );
+ Xor( from, BB_BOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = FirstOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_gold_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_BTGOLD );
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(BOARD[from]) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_BTGOLD );
+ }
+
+ BBAnd( bb, BB_BSILVER, b_chk_tbl[SQ_WKING].silver );
+ while ( bb.p[0] ) {
+ from = last_one0( bb.p[0] );
+ bb.p[0] ^= abb_mask[from].p[0];
+
+ bb_check_pro.p[0] = bb_move.p[0] & abb_b_silver_attacks[from].p[0]
+ & abb_w_gold_attacks[SQ_WKING].p[0];
+ bb_check_pro.p[1] = bb_move.p[1] & abb_b_silver_attacks[from].p[1]
+ & abb_w_gold_attacks[SQ_WKING].p[1];
+
+ bb_check.p[0] = bb_move.p[0] & abb_b_silver_attacks[from].p[0]
+ & abb_w_silver_attacks[SQ_WKING].p[0]
+ & ~abb_w_gold_attacks[SQ_WKING].p[0];
+ bb_check.p[1] = bb_move.p[1] & abb_b_silver_attacks[from].p[1]
+ & abb_w_silver_attacks[SQ_WKING].p[1]
+ & ~abb_w_gold_attacks[SQ_WKING].p[1];
+
+ if ( ! ( bb_check_pro.p[0] | bb_check_pro.p[1]
+ | bb_check.p[0]| bb_check.p[1] ) ) { continue; }
+
+ BB_BSILVER.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ while ( bb_check_pro.p[0] | bb_check_pro.p[1] ) {
+ to = first_one01( bb_check_pro.p[0], bb_check_pro.p[1] );
+ bb_check_pro.p[0] ^= abb_mask[to].p[0];
+ bb_check_pro.p[1] ^= abb_mask[to].p[1];
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_gold_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BSILVER.p[0] ^= abb_mask[from].p[0];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+ }
+
+ while ( bb_check.p[0] | bb_check.p[1] ) {
+ to = first_one01( bb_check.p[0], bb_check.p[1] );
+ bb_check.p[0] ^= abb_mask[to].p[0];
+ bb_check.p[1] ^= abb_mask[to].p[1];
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_silver_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BSILVER.p[0] ^= abb_mask[from].p[0];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+ }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BSILVER.p[0] ^= abb_mask[from].p[0];
+ }
+
+ ubb = bb.p[1] & 0x7fc0000U;
+ while ( ubb ) {
+ from = last_one1( ubb );
+ ubb ^= abb_mask[from].p[1];
+
+ bb_check_pro.p[0] = bb_move.p[0] & abb_b_silver_attacks[from].p[0]
+ & abb_w_gold_attacks[SQ_WKING].p[0];
+
+ bb_check.p[0] = bb_move.p[0] & abb_b_silver_attacks[from].p[0]
+ & abb_w_silver_attacks[SQ_WKING].p[0]
+ & ~abb_w_gold_attacks[SQ_WKING].p[0];
+ bb_check.p[1] = bb_move.p[1] & abb_b_silver_attacks[from].p[1]
+ & abb_w_silver_attacks[SQ_WKING].p[1];
+
+ if ( ! (bb_check_pro.p[0]|bb_check.p[0]|bb_check.p[1]) ) { continue; }
+
+ BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ while ( bb_check_pro.p[0] ) {
+ to = last_one0( bb_check_pro.p[0] );
+ bb_check_pro.p[0] ^= abb_mask[to].p[0];
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_gold_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+ }
+
+ while ( bb_check.p[0] | bb_check.p[1] ) {
+ to = first_one01( bb_check.p[0], bb_check.p[1] );
+ bb_check.p[0] ^= abb_mask[to].p[0];
+ bb_check.p[1] ^= abb_mask[to].p[1];
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_silver_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+ }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+ }
+
+ bb.p[1] &= 0x003ffffU;
+ while ( bb.p[1] | bb.p[2] ) {
+ from = first_one12( bb.p[1], bb.p[2] );
+ bb.p[1] ^= abb_mask[from].p[1];
+ bb.p[2] ^= abb_mask[from].p[2];
+
+ bb_check.p[1] = bb_move.p[1] & abb_b_silver_attacks[from].p[1]
+ & abb_w_silver_attacks[SQ_WKING].p[1];
+ bb_check.p[2] = bb_move.p[2] & abb_b_silver_attacks[from].p[2]
+ & abb_w_silver_attacks[SQ_WKING].p[2];
+ if ( ! ( bb_check.p[1] | bb_check.p[2] ) ) { continue; }
+
+ BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+ BB_BSILVER.p[2] ^= abb_mask[from].p[2];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = first_one12( bb_check.p[1], bb_check.p[2] );
+ bb_check.p[1] ^= abb_mask[to].p[1];
+ bb_check.p[2] ^= abb_mask[to].p[2];
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_silver_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+ BB_BSILVER.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(silver) );
+ } while ( bb_check.p[1] | bb_check.p[2] );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_BSILVER.p[1] ^= abb_mask[from].p[1];
+ BB_BSILVER.p[2] ^= abb_mask[from].p[2];
+ }
+
+ BBAnd( bb, BB_BKNIGHT, b_chk_tbl[SQ_WKING].knight );
+ while ( BBToU(bb) ) {
+ from = FirstOne( bb );
+ Xor( from, bb );
+
+ bb_check.p[0] = bb_move.p[0] & abb_b_knight_attacks[from].p[0]
+ & abb_w_gold_attacks[SQ_WKING].p[0];
+
+ if ( bb_check.p[0] ) {
+ BB_BKNIGHT.p[0] ^= abb_mask[from].p[0];
+ BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = last_one0( bb_check.p[0] );
+ bb_check.p[0] ^= abb_mask[to].p[0];
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_gold_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BKNIGHT.p[0] ^= abb_mask[from].p[0];
+ BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(-BOARD[to]) | Piece2Move(knight) );
+ } while ( bb_check.p[0] );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BKNIGHT.p[0] ^= abb_mask[from].p[0];
+ BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+ } else {
+
+ BBAnd( bb_check, bb_move, abb_b_knight_attacks[from] );
+ BBAnd( bb_check, bb_check, abb_w_knight_attacks[SQ_WKING] );
+
+ if ( BBToU(bb_check) ) {
+ BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+ BB_BKNIGHT.p[2] ^= abb_mask[from].p[2];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = FirstOne( bb_check );
+ Xor( to, bb_check );
+
+ BBIni( bb_attacks );
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+ BB_BKNIGHT.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(knight) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_BKNIGHT.p[1] ^= abb_mask[from].p[1];
+ BB_BKNIGHT.p[2] ^= abb_mask[from].p[2];
+ }
+ }
+ }
+
+ BBAnd( bb, BB_BLANCE, b_chk_tbl[SQ_WKING].lance );
+ while ( BBToU(bb) ) {
+ from = FirstOne( bb );
+ Xor( from, bb );
+
+ bb_attacks = AttackFile(from);
+ BBAnd( bb_attacks, bb_attacks, abb_minus_rays[from] );
+ BBAnd( bb_attacks, bb_attacks, bb_move );
+
+ BBAnd( bb_check, bb_attacks, abb_mask[SQ_WKING+nfile] );
+ bb_check_pro.p[0] = bb_attacks.p[0] & abb_w_gold_attacks[SQ_WKING].p[0];
+
+ if ( ! ( bb_check_pro.p[0] | bb_check.p[0]
+ | bb_check.p[1] | bb_check.p[2] ) ) { continue; }
+
+ Xor( from, BB_BLANCE );
+ Xor( from, BB_BOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ bb_check.p[0] &= 0x1ffU;
+ if ( BBToU(bb_check) ) {
+
+ to = SQ_WKING+nfile;
+ if ( ! is_white_attacked( ptree, to ) ) {
+ bb_check.p[0] &= ~abb_mask[to].p[0];
+ goto b_lance_next;
+ }
+ bb_temp = abb_file_attacks[to][0];
+ if ( can_w_king_escape( ptree, to, bb_temp ) ) { goto b_lance_next; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { goto b_lance_next; }
+ if ( IsDiscoverBK( from, to ) ) { goto b_lance_next; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_BLANCE );
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(lance) );
+ }
+
+ b_lance_next:
+ while ( bb_check_pro.p[0] )
+ {
+ to = last_one0( bb_check_pro.p[0] );
+ bb_check_pro.p[0] ^= abb_mask[to].p[0];
+
+ if ( ! is_white_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_b_gold_attacks[to];
+ if ( can_w_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_BLANCE );
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(-BOARD[to]) | Piece2Move(lance) );
+ }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_BOCCUPY );
+ Xor( from, BB_BLANCE );
+ }
+
+ bb_check.p[0] = bb_move.p[0] & BB_BPAWN_ATK.p[0]
+ & abb_w_gold_attacks[SQ_WKING].p[0];
+ while ( bb_check.p[0] ) {
+ to = last_one0( bb_check.p[0] );
+ from = to + nfile;
+ bb_check.p[0] ^= abb_mask[to].p[0];
+
+ BB_BPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+ BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ if ( ! is_white_attacked( ptree, to ) ) { goto b_pawn_pro_next; }
+ bb_attacks = abb_b_gold_attacks[to];
+ if ( can_w_king_escape( ptree,to,bb_attacks ) ) { goto b_pawn_pro_next; }
+ if ( IsDiscoverWK( from, to ) );
+ else if ( can_w_piece_capture( ptree, to ) ) { goto b_pawn_pro_next; }
+ if ( IsDiscoverBK( from, to ) ) { goto b_pawn_pro_next; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+ BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(-BOARD[to]) | Piece2Move(pawn) );
+
+ b_pawn_pro_next:
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+ BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ }
+
+ if ( SQ_WKING >= A7 && SQ_WKING <= I3 ) {
+ to = SQ_WKING + nfile;
+ from = to + nfile;
+ if ( BOARD[from] == pawn && BOARD[to] <= 0 ) {
+
+ BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ BB_BPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ if ( ! is_white_attacked( ptree, to ) ) { goto b_pawn_end; }
+ BBIni( bb_attacks );
+ if ( can_w_king_escape( ptree,to,bb_attacks ) ) { goto b_pawn_end; }
+ if ( can_w_piece_capture( ptree, to ) ) { goto b_pawn_end; }
+ if ( IsDiscoverBK( from, to ) ) { goto b_pawn_end; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ BB_BPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(pawn) );
+
+ b_pawn_end:
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_BOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_BOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_BPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ BB_BPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+ }
+ }
+
+ return 0;
+}
+
+
+unsigned int
+is_w_mate_in_1ply( tree_t * restrict ptree )
+{
+ bitboard_t bb, bb_temp, bb_check, bb_check_pro, bb_attacks, bb_drop, bb_move;
+ unsigned int ubb;
+ int to, from, idirec;
+
+ assert( ! is_white_attacked( ptree, SQ_WKING ) );
+
+ /* Drops */
+ BBOr( bb_drop, BB_BOCCUPY, BB_WOCCUPY );
+ BBNot( bb_drop, bb_drop );
+
+ if ( IsHandRook(HAND_W) ) {
+
+ BBAnd( bb, abb_w_gold_attacks[SQ_BKING],
+ abb_b_gold_attacks[SQ_BKING] );
+ BBAnd( bb, bb, bb_drop );
+ while( BBToU(bb) )
+ {
+ to = LastOne( bb );
+ Xor( to, bb );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(rook);
+ }
+
+ } else if ( IsHandLance(HAND_W) && SQ_BKING >= A8 ) {
+
+ to = SQ_BKING-nfile;
+ if ( ( ! BOARD[to] ) && is_black_attacked( ptree, to ) )
+ {
+ bb_attacks = abb_file_attacks[to][0];
+ if ( ( ! can_b_king_escape( ptree, to, bb_attacks ) )
+ && ( ! can_b_piece_capture( ptree, to ) ) )
+ {
+ return To2Move(to) | Drop2Move(lance);
+ }
+ }
+ }
+
+ if ( IsHandBishop(HAND_W) ) {
+
+ BBAnd( bb, abb_w_silver_attacks[SQ_BKING],
+ abb_b_silver_attacks[SQ_BKING] );
+ BBAnd( bb, bb, bb_drop );
+ while( BBToU(bb) )
+ {
+ to = LastOne( bb );
+ Xor( to, bb );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+ abb_bishop_attacks_rl45[to][0] );
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(bishop);
+ }
+ }
+
+ if ( IsHandGold(HAND_W) ) {
+
+ if ( IsHandRook(HAND_W) )
+ {
+ BBAnd( bb, abb_w_gold_attacks[SQ_BKING],
+ abb_w_silver_attacks[SQ_BKING] );
+ BBNot( bb, bb );
+ BBAnd( bb, bb, bb_drop );
+ BBAnd( bb, bb, abb_b_gold_attacks[SQ_BKING] );
+ }
+ else { BBAnd( bb, bb_drop, abb_b_gold_attacks[SQ_BKING] ); }
+
+ while ( BBToU(bb) )
+ {
+ to = LastOne( bb );
+ Xor( to, bb );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_gold_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(gold);
+ }
+ }
+
+ if ( IsHandSilver(HAND_W) ) {
+
+ if ( IsHandGold(HAND_W) )
+ {
+ if ( IsHandBishop(HAND_W) ) { goto w_silver_drop_end; }
+ BBNot( bb, abb_b_gold_attacks[SQ_BKING] );
+ BBAnd( bb, bb, abb_b_silver_attacks[SQ_BKING] );
+ BBAnd( bb, bb, bb_drop );
+ }
+ else {
+ BBAnd( bb, bb_drop, abb_b_silver_attacks[SQ_BKING] );
+ if ( IsHandBishop(HAND_W) )
+ {
+ BBAnd( bb, bb, abb_b_gold_attacks[SQ_BKING] );
+ }
+ }
+
+ while ( BBToU(bb) )
+ {
+ to = LastOne( bb );
+ Xor( to, bb );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_silver_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(silver);
+ }
+ }
+ w_silver_drop_end:
+
+ if ( IsHandKnight(HAND_W) ) {
+
+ BBAnd( bb, bb_drop, abb_b_knight_attacks[SQ_BKING] );
+ while ( BBToU(bb) )
+ {
+ to = LastOne( bb );
+ Xor( to, bb );
+
+ BBIni( bb_attacks );
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ return To2Move(to) | Drop2Move(knight);
+ }
+ }
+
+ /* Moves */
+ BBNot( bb_move, BB_WOCCUPY );
+
+ bb = BB_WDRAGON;
+ while ( BBToU(bb) ) {
+ from = LastOne( bb );
+ Xor( from, bb );
+
+ AttackDragon( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ BBAnd( bb_check, bb_check, abb_king_attacks[SQ_BKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ Xor( from, BB_W_HDK );
+ Xor( from, BB_W_RD );
+ Xor( from, BB_WOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = LastOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ if ( (int)adirec[SQ_BKING][to] & flag_cross )
+ {
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+ }
+ else { AttackDragon( bb_attacks, to ); }
+
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_W_RD );
+ Xor( from, BB_W_HDK );
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(dragon) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_W_RD );
+ Xor( from, BB_W_HDK );
+ }
+
+ bb.p[2] = BB_WROOK.p[2];
+ while ( bb.p[2] ) {
+ from = first_one2( bb.p[2] );
+ bb.p[2] ^= abb_mask[from].p[2];
+
+ AttackRook( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ BBAnd( bb_check, bb_check, abb_king_attacks[SQ_BKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ BB_W_RD.p[2] ^= abb_mask[from].p[2];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = LastOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ if ( (int)adirec[SQ_BKING][to] & flag_cross )
+ {
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+ }
+ else { AttackDragon( bb_attacks, to ); }
+
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_W_RD.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(BOARD[to]) | Piece2Move(rook) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_W_RD.p[2] ^= abb_mask[from].p[2];
+ }
+
+ bb.p[0] = BB_WROOK.p[0];
+ bb.p[1] = BB_WROOK.p[1];
+ while ( bb.p[0] | bb.p[1] ) {
+ from = last_one01( bb.p[0], bb.p[1] );
+ bb.p[0] ^= abb_mask[from].p[0];
+ bb.p[1] ^= abb_mask[from].p[1];
+
+ AttackRook( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ bb_check.p[0] &= abb_b_gold_attacks[SQ_BKING].p[0];
+ bb_check.p[1] &= abb_b_gold_attacks[SQ_BKING].p[1];
+ bb_check.p[0] &= abb_w_gold_attacks[SQ_BKING].p[0];
+ bb_check.p[1] &= abb_w_gold_attacks[SQ_BKING].p[1];
+ bb_check.p[2] &= abb_king_attacks[SQ_BKING].p[2];
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ BB_W_RD.p[0] ^= abb_mask[from].p[0];
+ BB_W_RD.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = LastOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ if ( to >= A3 ) {
+ if ( (int)adirec[SQ_BKING][to] & flag_cross )
+ {
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ bb_attacks.p[1] |= abb_king_attacks[to].p[1];
+ bb_attacks.p[2] |= abb_king_attacks[to].p[2];
+ }
+ else { AttackDragon( bb_attacks, to ); }
+ } else {
+ bb_attacks = abb_file_attacks[to][0];
+ bb_attacks.p[aslide[to].ir0] |= ai_rook_attacks_r0[to][0];
+ }
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_W_RD.p[0] ^= abb_mask[from].p[0];
+ BB_W_RD.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from)
+ | ( (to > I4) ? FLAG_PROMO : 0 )
+ | Cap2Move(BOARD[to]) | Piece2Move(rook) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_W_RD.p[0] ^= abb_mask[from].p[0];
+ BB_W_RD.p[1] ^= abb_mask[from].p[1];
+ }
+
+ bb = BB_WHORSE;
+ while ( BBToU(bb) ) {
+ from = LastOne( bb );
+ Xor( from, bb );
+
+ AttackHorse( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ BBAnd( bb_check, bb_check, abb_king_attacks[SQ_BKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ Xor( from, BB_W_HDK );
+ Xor( from, BB_W_BH );
+ Xor( from, BB_WOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = LastOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+ abb_bishop_attacks_rl45[to][0] );
+ BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_W_BH );
+ Xor( from, BB_W_HDK );
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(horse) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_W_BH );
+ Xor( from, BB_W_HDK );
+ }
+
+ bb.p[2] = BB_WBISHOP.p[2];
+ while ( bb.p[2] ) {
+ from = first_one2( bb.p[2] );
+ bb.p[2] ^= abb_mask[from].p[2];
+
+ AttackBishop( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ BBAnd( bb_check, bb_check, abb_king_attacks[SQ_BKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ BB_W_BH.p[2] ^= abb_mask[from].p[2];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = LastOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+ abb_bishop_attacks_rl45[to][0] );
+ BBOr( bb_attacks, bb_attacks, abb_king_attacks[to] );
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_W_BH.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(BOARD[to]) | Piece2Move(bishop) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_W_BH.p[2] ^= abb_mask[from].p[2];
+ }
+
+ bb.p[0] = BB_WBISHOP.p[0];
+ bb.p[1] = BB_WBISHOP.p[1];
+ while ( bb.p[0] | bb.p[1] ) {
+ from = last_one01( bb.p[0], bb.p[1] );
+ bb.p[0] ^= abb_mask[from].p[0];
+ bb.p[1] ^= abb_mask[from].p[1];
+
+ AttackBishop( bb_attacks, from );
+ BBAnd( bb_check, bb_move, bb_attacks );
+ bb_check.p[0] &= abb_b_silver_attacks[SQ_BKING].p[0];
+ bb_check.p[1] &= abb_b_silver_attacks[SQ_BKING].p[1];
+ bb_check.p[0] &= abb_w_silver_attacks[SQ_BKING].p[0];
+ bb_check.p[1] &= abb_w_silver_attacks[SQ_BKING].p[1];
+ bb_check.p[2] &= abb_king_attacks[SQ_BKING].p[2];
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ BB_W_BH.p[0] ^= abb_mask[from].p[0];
+ BB_W_BH.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = LastOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ BBOr( bb_attacks, abb_bishop_attacks_rr45[to][0],
+ abb_bishop_attacks_rl45[to][0] );
+ if ( to >= A3 ) {
+ bb_attacks.p[1] |= abb_king_attacks[to].p[1];
+ bb_attacks.p[2] |= abb_king_attacks[to].p[2];
+ }
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_W_BH.p[0] ^= abb_mask[from].p[0];
+ BB_W_BH.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from)
+ | ( (to > I4) ? FLAG_PROMO : 0 )
+ | Cap2Move(BOARD[to]) | Piece2Move(bishop) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_W_BH.p[0] ^= abb_mask[from].p[0];
+ BB_W_BH.p[1] ^= abb_mask[from].p[1];
+ }
+
+ BBAnd( bb, BB_WTGOLD, w_chk_tbl[SQ_BKING].gold );
+ while ( BBToU(bb) ) {
+ from = LastOne( bb );
+ Xor( from, bb );
+
+ BBAnd( bb_check, bb_move, abb_w_gold_attacks[from] );
+ BBAnd( bb_check, bb_check, abb_b_gold_attacks[SQ_BKING] );
+ if ( ! BBToU(bb_check) ) { continue; }
+
+ Xor( from, BB_WTGOLD );
+ Xor( from, BB_WOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = LastOne( bb_check );
+ Xor( to, bb_check );
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_gold_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_WTGOLD );
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(-BOARD[from]) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_WTGOLD );
+ }
+
+ BBAnd( bb, BB_WSILVER, w_chk_tbl[SQ_BKING].silver );
+ while ( bb.p[2] ) {
+ from = first_one2( bb.p[2] );
+ bb.p[2] ^= abb_mask[from].p[2];
+
+ bb_check_pro.p[1] = bb_move.p[1] & abb_w_silver_attacks[from].p[1]
+ & abb_b_gold_attacks[SQ_BKING].p[1];
+ bb_check_pro.p[2] = bb_move.p[2] & abb_w_silver_attacks[from].p[2]
+ & abb_b_gold_attacks[SQ_BKING].p[2];
+
+ bb_check.p[1] = bb_move.p[1] & abb_w_silver_attacks[from].p[1]
+ & abb_b_silver_attacks[SQ_BKING].p[1]
+ & ~abb_b_gold_attacks[SQ_BKING].p[1];
+ bb_check.p[2] = bb_move.p[2] & abb_w_silver_attacks[from].p[2]
+ & abb_b_silver_attacks[SQ_BKING].p[2]
+ & ~abb_b_gold_attacks[SQ_BKING].p[2];
+
+ if ( ! ( bb_check_pro.p[1] | bb_check_pro.p[2]
+ | bb_check.p[1]| bb_check.p[2] ) ) { continue; }
+
+ BB_WSILVER.p[2] ^= abb_mask[from].p[2];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ while ( bb_check_pro.p[1] | bb_check_pro.p[2] ) {
+ to = last_one12( bb_check_pro.p[1], bb_check_pro.p[2] );
+ bb_check_pro.p[1] ^= abb_mask[to].p[1];
+ bb_check_pro.p[2] ^= abb_mask[to].p[2];
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_gold_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_WSILVER.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+ }
+
+ while ( bb_check.p[1] | bb_check.p[2] ) {
+ to = last_one12( bb_check.p[1], bb_check.p[2] );
+ bb_check.p[1] ^= abb_mask[to].p[1];
+ bb_check.p[2] ^= abb_mask[to].p[2];
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_silver_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_WSILVER.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+ }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_WSILVER.p[2] ^= abb_mask[from].p[2];
+ }
+
+ ubb = bb.p[1] & 0x1ffU;
+ while ( ubb ) {
+ from = first_one1( ubb );
+ ubb ^= abb_mask[from].p[1];
+
+ bb_check_pro.p[2] = bb_move.p[2] & abb_w_silver_attacks[from].p[2]
+ & abb_b_gold_attacks[SQ_BKING].p[2];
+
+ bb_check.p[2] = bb_move.p[2] & abb_w_silver_attacks[from].p[2]
+ & abb_b_silver_attacks[SQ_BKING].p[2]
+ & ~abb_b_gold_attacks[SQ_BKING].p[2];
+ bb_check.p[1] = bb_move.p[1] & abb_w_silver_attacks[from].p[1]
+ & abb_b_silver_attacks[SQ_BKING].p[1];
+
+ if ( ! (bb_check_pro.p[2]|bb_check.p[2]|bb_check.p[1]) ) { continue; }
+
+ BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ while ( bb_check_pro.p[2] ) {
+ to = first_one2( bb_check_pro.p[2] );
+ bb_check_pro.p[2] ^= abb_mask[to].p[2];
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_gold_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+ }
+
+ while ( bb_check.p[1] | bb_check.p[2] ) {
+ to = last_one12( bb_check.p[1], bb_check.p[2] );
+ bb_check.p[1] ^= abb_mask[to].p[1];
+ bb_check.p[2] ^= abb_mask[to].p[2];
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_silver_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+ }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+ }
+
+ bb.p[0] = bb.p[0];
+ bb.p[1] = bb.p[1] & 0x7fffe00U;
+ while ( bb.p[0] | bb.p[1] ) {
+ from = last_one01( bb.p[0], bb.p[1] );
+ bb.p[0] ^= abb_mask[from].p[0];
+ bb.p[1] ^= abb_mask[from].p[1];
+
+ bb_check.p[0] = bb_move.p[0] & abb_w_silver_attacks[from].p[0]
+ & abb_b_silver_attacks[SQ_BKING].p[0];
+ bb_check.p[1] = bb_move.p[1] & abb_w_silver_attacks[from].p[1]
+ & abb_b_silver_attacks[SQ_BKING].p[1];
+ if ( ! ( bb_check.p[0] | bb_check.p[1] ) ) { continue; }
+
+ BB_WSILVER.p[0] ^= abb_mask[from].p[0];
+ BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = last_one01( bb_check.p[0], bb_check.p[1] );
+ bb_check.p[0] ^= abb_mask[to].p[0];
+ bb_check.p[1] ^= abb_mask[to].p[1];
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_silver_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WSILVER.p[0] ^= abb_mask[from].p[0];
+ BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(silver) );
+ } while ( bb_check.p[0] | bb_check.p[1] );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WSILVER.p[0] ^= abb_mask[from].p[0];
+ BB_WSILVER.p[1] ^= abb_mask[from].p[1];
+ }
+
+ BBAnd( bb, BB_WKNIGHT, w_chk_tbl[SQ_BKING].knight );
+ while ( BBToU(bb) ) {
+ from = LastOne( bb );
+ Xor( from, bb );
+
+ bb_check.p[2] = bb_move.p[2] & abb_w_knight_attacks[from].p[2]
+ & abb_b_gold_attacks[SQ_BKING].p[2];
+
+ if ( bb_check.p[2] ) {
+ BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+ BB_WKNIGHT.p[2] ^= abb_mask[from].p[2];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = first_one2( bb_check.p[2] );
+ bb_check.p[2] ^= abb_mask[to].p[2];
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_gold_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+ BB_WKNIGHT.p[2] ^= abb_mask[from].p[2];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(BOARD[to]) | Piece2Move(knight) );
+ } while ( bb_check.p[2] );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+ BB_WKNIGHT.p[2] ^= abb_mask[from].p[2];
+ } else {
+
+ BBAnd( bb_check, bb_move, abb_w_knight_attacks[from] );
+ BBAnd( bb_check, bb_check, abb_b_knight_attacks[SQ_BKING] );
+
+ if ( BBToU(bb_check) ) {
+ BB_WKNIGHT.p[0] ^= abb_mask[from].p[0];
+ BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ do {
+ to = LastOne( bb_check );
+ Xor( to, bb_check );
+
+ BBIni( bb_attacks );
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WKNIGHT.p[0] ^= abb_mask[from].p[0];
+ BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(knight) );
+ } while ( BBToU(bb_check) );
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WKNIGHT.p[0] ^= abb_mask[from].p[0];
+ BB_WKNIGHT.p[1] ^= abb_mask[from].p[1];
+ }
+ }
+ }
+
+ BBAnd( bb, BB_WLANCE, w_chk_tbl[SQ_BKING].lance );
+ while ( BBToU(bb) ) {
+ from = LastOne( bb );
+ Xor( from, bb );
+
+ bb_attacks = AttackFile(from);
+ BBAnd( bb_attacks, bb_attacks, abb_plus_rays[from] );
+ BBAnd( bb_attacks, bb_attacks, bb_move );
+
+ BBAnd( bb_check, bb_attacks, abb_mask[SQ_BKING-nfile] );
+ bb_check_pro.p[2] = bb_attacks.p[2] & abb_b_gold_attacks[SQ_BKING].p[2];
+
+ if ( ! ( bb_check_pro.p[2] | bb_check.p[0]
+ | bb_check.p[1] | bb_check.p[2] ) ) { continue; }
+
+ Xor( from, BB_WLANCE );
+ Xor( from, BB_WOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ bb_check.p[2] &= 0x7fc0000U;
+ if ( BBToU(bb_check) ) {
+
+ to = SQ_BKING-nfile;
+ if ( ! is_black_attacked( ptree, to ) ) {
+ bb_check.p[2] &= ~abb_mask[to].p[2];
+ goto w_lance_next;
+ }
+ bb_temp = abb_file_attacks[to][0];
+ if ( can_b_king_escape( ptree, to, bb_temp ) ) { goto w_lance_next; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { goto w_lance_next; }
+ if ( IsDiscoverWK( from, to ) ) { goto w_lance_next; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_WLANCE );
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(lance) );
+ }
+
+ w_lance_next:
+ while ( bb_check_pro.p[2] )
+ {
+ to = first_one2( bb_check_pro.p[2] );
+ bb_check_pro.p[2] ^= abb_mask[to].p[2];
+
+ if ( ! is_black_attacked( ptree, to ) ) { continue; }
+
+ bb_attacks = abb_w_gold_attacks[to];
+ if ( can_b_king_escape( ptree, to, bb_attacks ) ) { continue; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { continue; }
+ if ( IsDiscoverWK( from, to ) ) { continue; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_WLANCE );
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(BOARD[to]) | Piece2Move(lance) );
+ }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ Xor( from, BB_WOCCUPY );
+ Xor( from, BB_WLANCE );
+ }
+
+ bb_check.p[2] = bb_move.p[2] & BB_WPAWN_ATK.p[2]
+ & abb_b_gold_attacks[SQ_BKING].p[2];
+ while ( bb_check.p[2] ) {
+ to = first_one2( bb_check.p[2] );
+ from = to - nfile;
+ bb_check.p[2] ^= abb_mask[to].p[2];
+
+ BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ BB_WPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ if ( ! is_black_attacked( ptree, to ) ) { goto w_pawn_pro_next; }
+ bb_attacks = abb_w_gold_attacks[to];
+ if ( can_b_king_escape( ptree,to,bb_attacks ) ) { goto w_pawn_pro_next; }
+ if ( IsDiscoverBK( from, to ) );
+ else if ( can_b_piece_capture( ptree, to ) ) { goto w_pawn_pro_next; }
+ if ( IsDiscoverWK( from, to ) ) { goto w_pawn_pro_next; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ BB_WPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+ return ( To2Move(to) | From2Move(from) | FLAG_PROMO
+ | Cap2Move(BOARD[to]) | Piece2Move(pawn) );
+
+ w_pawn_pro_next:
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WOCCUPY.p[2] ^= abb_mask[from].p[2];
+ BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ BB_WPAWN_ATK.p[2] ^= abb_mask[to].p[2];
+ }
+
+ if ( SQ_BKING <= I3 && SQ_BKING >= A7 ) {
+ to = SQ_BKING - nfile;
+ from = to - nfile;
+ if ( BOARD[from] == -pawn && BOARD[to] >= 0 ) {
+
+ BB_WPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+ BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+
+ if ( ! is_black_attacked( ptree, to ) ) { goto w_pawn_end; }
+ BBIni( bb_attacks );
+ if ( can_b_king_escape( ptree,to,bb_attacks ) ) { goto w_pawn_end; }
+ if ( can_b_piece_capture( ptree, to ) ) { goto w_pawn_end; }
+ if ( IsDiscoverWK( from, to ) ) { goto w_pawn_end; }
+
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+ BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ return ( To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(pawn) );
+
+ w_pawn_end:
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ BB_WOCCUPY.p[0] ^= abb_mask[from].p[0];
+ BB_WOCCUPY.p[1] ^= abb_mask[from].p[1];
+ BB_WPAWN_ATK.p[0] ^= abb_mask[to].p[0];
+ BB_WPAWN_ATK.p[1] ^= abb_mask[to].p[1];
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+can_w_piece_capture( const tree_t * restrict ptree, int to )
+{
+ bitboard_t bb_sum, bb, bb_attacks;
+ int idirec, from;
+
+ from = to-nfile;
+ if ( to >= A8 && BOARD[from] == -pawn )
+ {
+ if ( IsDiscoverWK(from,to) );
+ else { return 1; }
+ }
+
+ BBAnd( bb_sum, BB_WKNIGHT, abb_b_knight_attacks[to] );
+
+ BBAnd( bb, BB_WSILVER, abb_b_silver_attacks[to] );
+ BBOr( bb_sum, bb, bb_sum );
+
+ BBAnd( bb, BB_WTGOLD, abb_b_gold_attacks[to] );
+ BBOr( bb_sum, bb, bb_sum );
+
+ BBOr( bb, BB_WHORSE, BB_WDRAGON );
+ BBAnd( bb, bb, abb_king_attacks[to] );
+ BBOr( bb_sum, bb, bb_sum );
+
+ AttackBishop( bb, to );
+ BBAnd( bb, BB_W_BH, bb );
+ BBOr( bb_sum, bb, bb_sum );
+
+ bb_sum.p[aslide[to].ir0] |= BB_W_RD.p[aslide[to].ir0] & AttackRank(to);
+
+ BBAnd( bb, BB_WLANCE, abb_minus_rays[to] );
+ BBOr( bb, bb, BB_W_RD );
+ bb_attacks = AttackFile( to );
+ BBAnd( bb, bb, bb_attacks );
+ BBOr( bb_sum, bb_sum, bb );
+
+ while ( BBToU( bb_sum ) )
+ {
+ from = FirstOne( bb_sum );
+ Xor( from, bb_sum );
+
+ if ( IsDiscoverWK(from,to) ) { continue; }
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+can_b_piece_capture( const tree_t * restrict ptree, int to )
+{
+ bitboard_t bb_sum, bb, bb_attacks;
+ int idirec, from;
+
+ from = to+nfile;
+ if ( to <= I2 && BOARD[from] == pawn )
+ {
+ if ( IsDiscoverBK(from,to) );
+ else { return 1; }
+ }
+
+ BBAnd( bb_sum, BB_BKNIGHT, abb_w_knight_attacks[to] );
+
+ BBAnd( bb, BB_BSILVER, abb_w_silver_attacks[to] );
+ BBOr( bb_sum, bb_sum, bb );
+
+ BBAnd( bb, BB_BTGOLD, abb_w_gold_attacks[to] );
+ BBOr( bb_sum, bb_sum, bb );
+
+ BBOr( bb, BB_BHORSE, BB_BDRAGON );
+ BBAnd( bb, bb, abb_king_attacks[to] );
+ BBOr( bb_sum, bb_sum, bb );
+
+ AttackBishop( bb, to );
+ BBAnd( bb, bb, BB_B_BH );
+ BBOr( bb_sum, bb_sum, bb );
+
+ bb_sum.p[aslide[to].ir0] |= BB_B_RD.p[aslide[to].ir0] & AttackRank(to);
+
+ BBAnd( bb, BB_BLANCE, abb_plus_rays[to] );
+ BBOr( bb, bb, BB_B_RD );
+ bb_attacks = AttackFile( to );
+ BBAnd( bb, bb, bb_attacks );
+ BBOr( bb_sum, bb_sum, bb );
+
+ while ( BBToU( bb_sum ) )
+ {
+ from = LastOne( bb_sum );
+ Xor( from, bb_sum );
+
+ if ( IsDiscoverBK( from, to ) ) { continue; }
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+can_w_king_escape( tree_t * restrict ptree, int to, bitboard_t bb )
+{
+ int iret = 0, iescape;
+
+ if ( !BOARD[to] )
+ {
+ Xor( to, BB_BOCCUPY );
+ XorFile( to, OCCUPIED_FILE );
+ XorDiag2( to, OCCUPIED_DIAG2 );
+ XorDiag1( to, OCCUPIED_DIAG1 );
+ }
+ Xor( SQ_WKING, BB_WOCCUPY );
+ XorFile( SQ_WKING, OCCUPIED_FILE );
+ XorDiag2( SQ_WKING, OCCUPIED_DIAG2 );
+ XorDiag1( SQ_WKING, OCCUPIED_DIAG1 );
+
+ BBOr( bb, bb, abb_mask[to] );
+ BBOr( bb, bb, BB_WOCCUPY );
+ BBNot( bb, bb );
+ BBAnd( bb, bb, abb_king_attacks[SQ_WKING] );
+
+ while( BBToU(bb) )
+ {
+ iescape = FirstOne( bb );
+ if ( ! is_white_attacked( ptree, iescape ) )
+ {
+ iret = 1;
+ break;
+ }
+ Xor( iescape, bb );
+ }
+
+ XorFile( SQ_WKING, OCCUPIED_FILE );
+ XorDiag2( SQ_WKING, OCCUPIED_DIAG2 );
+ XorDiag1( SQ_WKING, OCCUPIED_DIAG1 );
+ Xor( SQ_WKING, BB_WOCCUPY );
+ if ( !BOARD[to] )
+ {
+ Xor( to, BB_BOCCUPY );
+ XorFile( to, OCCUPIED_FILE );
+ XorDiag2( to, OCCUPIED_DIAG2 );
+ XorDiag1( to, OCCUPIED_DIAG1 );
+ }
+
+ return iret;
+}
+
+
+static int
+can_b_king_escape( tree_t * restrict ptree, int to, bitboard_t bb )
+{
+ int iret = 0, iescape;
+
+ if ( !BOARD[to] )
+ {
+ Xor( to, BB_WOCCUPY );
+ XorFile( to, OCCUPIED_FILE );
+ XorDiag2( to, OCCUPIED_DIAG2 );
+ XorDiag1( to, OCCUPIED_DIAG1 );
+ }
+
+ Xor( SQ_BKING, BB_BOCCUPY );
+ XorFile( SQ_BKING, OCCUPIED_FILE );
+ XorDiag2( SQ_BKING, OCCUPIED_DIAG2 );
+ XorDiag1( SQ_BKING, OCCUPIED_DIAG1 );
+
+ BBOr( bb, bb, abb_mask[to] );
+ BBOr( bb, bb, BB_BOCCUPY );
+ BBNot( bb, bb );
+ BBAnd( bb, bb, abb_king_attacks[SQ_BKING] );
+
+ while( BBToU(bb) )
+ {
+ iescape = LastOne( bb );
+ if ( ! is_black_attacked( ptree, iescape ) )
+ {
+ iret = 1;
+ break;
+ }
+ Xor( iescape, bb );
+ }
+
+ XorFile( SQ_BKING, OCCUPIED_FILE );
+ XorDiag2( SQ_BKING, OCCUPIED_DIAG2 );
+ XorDiag1( SQ_BKING, OCCUPIED_DIAG1 );
+ Xor( SQ_BKING, BB_BOCCUPY );
+
+ if ( !BOARD[to] )
+ {
+ XorFile( to, OCCUPIED_FILE );
+ XorDiag2( to, OCCUPIED_DIAG2 );
+ XorDiag1( to, OCCUPIED_DIAG1 );
+ Xor( to, BB_WOCCUPY );
+ }
+
+ return iret;
+}
--- /dev/null
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+#include "shogi.h"
+
+enum { mate_king_cap_checker = 0,
+ mate_cap_checker_gen,
+ mate_cap_checker,
+ mate_king_cap_gen,
+ mate_king_cap,
+ mate_king_move_gen,
+ mate_king_move,
+ mate_intercept_move_gen,
+ mate_intercept_move,
+ mate_intercept_weak_move,
+ mate_intercept_drop_sup };
+
+static int mate3_and( tree_t * restrict ptree, int turn, int ply, int flag );
+static void checker( const tree_t * restrict ptree, char *psq, int turn );
+static unsigned int gen_king_cap_checker( const tree_t * restrict ptree,
+ int to, int turn );
+static int mate_weak_or( tree_t * restrict ptree, int turn, int ply,
+ int from, int to );
+static unsigned int *gen_move_to( const tree_t * restrict ptree, int sq,
+ int turn, unsigned int * restrict pmove );
+static unsigned int *gen_king_move( const tree_t * restrict ptree,
+ const char *psq, int turn, int is_capture,
+ unsigned int * restrict pmove );
+static unsigned int *gen_intercept( tree_t * restrict __ptree__,
+ int sq_checker, int ply, int turn,
+ int * restrict premaining,
+ unsigned int * restrict pmove, int flag );
+static int gen_next_evasion_mate( tree_t * restrict ptree, const char *psq,
+ int ply, int turn, int flag );
+
+unsigned int
+is_mate_in3ply( tree_t * restrict ptree, int turn, int ply )
+{
+ int value, flag_skip;
+
+ if ( ply >= PLY_MAX-2 ) { return 0; }
+
+ flag_skip = 0;
+
+ ptree->anext_move[ply].move_last = ptree->move_last[ply-1];
+ ptree->move_last[ply] = GenCheck( turn, ptree->move_last[ply-1] );
+
+ while ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+ {
+ MOVE_CURR = *ptree->anext_move[ply].move_last++;
+
+ if ( MOVE_CURR & MOVE_CHK_CLEAR ) { flag_skip = 0; }
+ if ( flag_skip ) { continue; }
+
+ assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+ MakeMove( turn, MOVE_CURR, ply );
+ if ( InCheck(turn) )
+ {
+ UnMakeMove( turn, MOVE_CURR, ply );
+ continue;
+ }
+
+ value = mate3_and( ptree, Flip(turn), ply+1, 0 );
+
+ UnMakeMove( turn, MOVE_CURR, ply );
+
+ if ( value ) { return 1; }
+
+ if ( ( MOVE_CURR & MOVE_CHK_SET )
+ && I2To(MOVE_CURR) != I2To(ptree->current_move[ply+1]) )
+ {
+ flag_skip = 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+mate3_and( tree_t * restrict ptree, int turn, int ply, int flag )
+{
+ unsigned int move;
+ char asq[2];
+
+ assert( InCheck(turn) );
+
+ ptree->anext_move[ply].next_phase = mate_king_cap_checker;
+ checker( ptree, asq, turn );
+
+ while ( gen_next_evasion_mate( ptree, asq, ply, turn, flag ) ) {
+
+ if ( ptree->anext_move[ply].next_phase == mate_intercept_drop_sup )
+ {
+ return 0;
+ }
+
+ MakeMove( turn, MOVE_CURR, ply );
+ assert( ! InCheck(turn) );
+
+ if ( InCheck( Flip(turn) ) ) { move = 0; }
+ else { move = IsMateIn1Ply( Flip(turn) ); }
+
+ if ( ! move
+ && ptree->anext_move[ply].next_phase == mate_intercept_weak_move )
+ {
+ assert( asq[1] == nsquare );
+ move = (unsigned int)mate_weak_or( ptree, Flip(turn), ply+1, asq[0],
+ I2To(MOVE_CURR) );
+ }
+
+ UnMakeMove( turn, MOVE_CURR, ply );
+
+ if ( ! move ) { return 0; }
+ }
+
+ return 1;
+}
+
+
+static int
+mate_weak_or( tree_t * restrict ptree, int turn, int ply, int from,
+ int to )
+{
+ int idirec, pc, pc_cap, value, flag;
+
+ if ( ply >= PLY_MAX-2 ) { return 0; }
+
+ if ( turn )
+ {
+ if ( IsDiscoverWK( from, to ) ) { return 0; }
+
+ pc = -BOARD[from];
+ pc_cap = BOARD[to];
+ MOVE_CURR = ( To2Move(to) | From2Move(from)
+ | Piece2Move(pc) | Cap2Move(pc_cap) );
+ if ( ( pc == bishop || pc == rook )
+ && ( to > I4 || from > I4 ) ) { MOVE_CURR |= FLAG_PROMO; }
+ }
+ else {
+ if ( IsDiscoverBK( from, to ) ) { return 0; }
+
+ pc = BOARD[from];
+ pc_cap = -BOARD[to];
+ MOVE_CURR = ( To2Move(to) | From2Move(from) | Piece2Move(pc)
+ | Cap2Move(pc_cap) );
+ if ( ( pc == bishop || pc == rook )
+ && ( to < A6 || from < A6 ) ) { MOVE_CURR |= FLAG_PROMO; }
+ }
+
+ MakeMove( turn, MOVE_CURR, ply );
+ if ( I2From(MOVE_LAST) < nsquare )
+ {
+ if ( InCheck(turn) )
+ {
+ UnMakeMove( turn, MOVE_CURR, ply );
+ return 0;
+ }
+ flag = 1;
+ }
+ else {
+ assert( ! InCheck(turn) );
+ flag = 2;
+ }
+
+ ptree->move_last[ply] = ptree->move_last[ply-1];
+ value = mate3_and( ptree, Flip(turn), ply+1, flag );
+
+ UnMakeMove( turn, MOVE_CURR, ply );
+
+ return value;
+}
+
+
+static int
+gen_next_evasion_mate( tree_t * restrict ptree, const char *psq, int ply,
+ int turn, int flag )
+{
+ switch ( ptree->anext_move[ply].next_phase )
+ {
+ case mate_king_cap_checker:
+ ptree->anext_move[ply].next_phase = mate_cap_checker_gen;
+ MOVE_CURR = gen_king_cap_checker( ptree, psq[0], turn );
+ if ( MOVE_CURR ) { return 1; }
+
+ case mate_cap_checker_gen:
+ ptree->anext_move[ply].next_phase = mate_cap_checker;
+ ptree->anext_move[ply].move_last = ptree->move_last[ply-1];
+ ptree->move_last[ply] = ptree->move_last[ply-1];
+ if ( psq[1] == nsquare )
+ {
+ ptree->move_last[ply]
+ = gen_move_to( ptree, psq[0], turn, ptree->move_last[ply-1] );
+ }
+
+ case mate_cap_checker:
+ if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+ {
+ MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+ return 1;
+ }
+
+ case mate_king_cap_gen:
+ ptree->anext_move[ply].next_phase = mate_king_cap;
+ ptree->anext_move[ply].move_last = ptree->move_last[ply-1];
+ ptree->move_last[ply]
+ = gen_king_move( ptree, psq, turn, 1, ptree->move_last[ply-1] );
+
+ case mate_king_cap:
+ if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+ {
+ MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+ return 1;
+ }
+
+ case mate_king_move_gen:
+ ptree->anext_move[ply].next_phase = mate_king_move;
+ ptree->anext_move[ply].move_last = ptree->move_last[ply-1];
+ ptree->move_last[ply]
+ = gen_king_move( ptree, psq, turn, 0, ptree->move_last[ply-1] );
+
+ case mate_king_move:
+ if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+ {
+ MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+ return 1;
+ }
+
+ case mate_intercept_move_gen:
+ ptree->anext_move[ply].remaining = 0;
+ ptree->anext_move[ply].next_phase = mate_intercept_move;
+ ptree->anext_move[ply].move_last = ptree->move_last[ply-1];
+ ptree->move_last[ply] = ptree->move_last[ply-1];
+ if ( psq[1] == nsquare && abs(BOARD[(int)psq[0]]) != knight )
+ {
+ int n;
+ ptree->move_last[ply] = gen_intercept( ptree, psq[0], ply, turn, &n,
+ ptree->move_last[ply-1],
+ flag );
+ if ( n < 0 )
+ {
+ ptree->anext_move[ply].next_phase = mate_intercept_drop_sup;
+ ptree->anext_move[ply].remaining = 0;
+ MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+ return 1;
+ }
+
+ ptree->anext_move[ply].remaining = n;
+ }
+
+ case mate_intercept_move:
+ if ( ptree->anext_move[ply].remaining-- )
+ {
+ MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+ return 1;
+ }
+ ptree->anext_move[ply].next_phase = mate_intercept_weak_move;
+
+ case mate_intercept_weak_move:
+ if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+ {
+ MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+ return 1;
+ }
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ return 0;
+}
+
+
+static void
+checker( const tree_t * restrict ptree, char *psq, int turn )
+{
+ bitboard_t bb, bb_checkers;
+ int n, sq0, sq1, sq_king;
+
+ if ( turn )
+ {
+ sq_king = SQ_WKING;
+ bb_checkers = BB_BOCCUPY;
+ }
+ else {
+ sq_king = SQ_BKING;
+ bb_checkers = BB_WOCCUPY;
+ }
+ bb = attacks_to_piece( ptree, sq_king );
+ BBAnd( bb, bb, bb_checkers );
+
+ assert( BBToU(bb) );
+ sq0 = LastOne( bb );
+ sq1 = nsquare;
+
+ Xor( sq0, bb );
+ if ( BBToU( bb ) )
+ {
+ sq1 = LastOne( bb );
+ if ( BBContract( abb_king_attacks[sq_king], abb_mask[sq1] ) )
+ {
+ n = sq0;
+ sq0 = sq1;
+ sq1 = n;
+ }
+ }
+
+ psq[0] = (char)sq0;
+ psq[1] = (char)sq1;
+}
+
+
+static unsigned int
+gen_king_cap_checker( const tree_t * restrict ptree, int to, int turn )
+{
+ unsigned int move;
+ int from;
+
+ if ( turn )
+ {
+ from = SQ_WKING;
+ if ( ! BBContract( abb_king_attacks[from],
+ abb_mask[to] ) ) { return 0;}
+ if ( is_white_attacked( ptree, to ) ) { return 0; }
+ move = Cap2Move(BOARD[to]);
+ }
+ else {
+ from = SQ_BKING;
+ if ( ! BBContract( abb_king_attacks[from],
+ abb_mask[to] ) ) { return 0;}
+ if ( is_black_attacked( ptree, to ) ) { return 0; }
+ move = Cap2Move(-BOARD[to]);
+ }
+ move |= To2Move(to) | From2Move(from) | Piece2Move(king);
+
+ return move;
+}
+
+
+static unsigned int *
+gen_move_to( const tree_t * restrict ptree, int to, int turn,
+ unsigned int * restrict pmove )
+{
+ bitboard_t bb;
+ int direc, from, pc, flag_promo, flag_unpromo;
+
+ bb = attacks_to_piece( ptree, to );
+ if ( turn )
+ {
+ BBAnd( bb, bb, BB_WOCCUPY );
+ BBNotAnd( bb, abb_mask[SQ_WKING] );
+ while ( BBToU(bb) )
+ {
+ from = LastOne( bb );
+ Xor( from, bb );
+
+ direc = (int)adirec[SQ_WKING][from];
+ if ( direc && is_pinned_on_white_king( ptree, from, direc ) )
+ {
+ continue;
+ }
+
+ flag_promo = 0;
+ flag_unpromo = 1;
+ pc = -BOARD[from];
+ switch ( pc )
+ {
+ case pawn:
+ if ( to > I4 ) { flag_promo = 1; flag_unpromo = 0; }
+ break;
+
+ case lance: case knight:
+ if ( to > I3 ) { flag_promo = 1; flag_unpromo = 0; }
+ else if ( to > I4 ) { flag_promo = 1; }
+ break;
+
+ case silver:
+ if ( to > I4 || from > I4 ) { flag_promo = 1; }
+ break;
+
+ case bishop: case rook:
+ if ( to > I4
+ || from > I4 ) { flag_promo = 1; flag_unpromo = 0; }
+ break;
+
+ default:
+ break;
+ }
+ assert( flag_promo || flag_unpromo );
+ if ( flag_promo )
+ {
+ *pmove++ = ( From2Move(from) | To2Move(to) | FLAG_PROMO
+ | Piece2Move(pc) | Cap2Move(BOARD[to]) );
+ }
+ if ( flag_unpromo )
+ {
+ *pmove++ = ( From2Move(from) | To2Move(to)
+ | Piece2Move(pc) | Cap2Move(BOARD[to]) );
+ }
+ }
+ }
+ else {
+ BBAnd( bb, bb, BB_BOCCUPY );
+ BBNotAnd( bb, abb_mask[SQ_BKING] );
+ while ( BBToU(bb) )
+ {
+ from = FirstOne( bb );
+ Xor( from, bb );
+
+ direc = (int)adirec[SQ_BKING][from];
+ if ( direc && is_pinned_on_black_king( ptree, from, direc ) )
+ {
+ continue;
+ }
+
+ flag_promo = 0;
+ flag_unpromo = 1;
+ pc = BOARD[from];
+ switch ( pc )
+ {
+ case pawn:
+ if ( to < A6 ) { flag_promo = 1; flag_unpromo = 0; }
+ break;
+
+ case lance: case knight:
+ if ( to < A7 ) { flag_promo = 1; flag_unpromo = 0; }
+ else if ( to < A6 ) { flag_promo = 1; }
+ break;
+
+ case silver:
+ if ( to < A6 || from < A6 ) { flag_promo = 1; }
+ break;
+
+ case bishop: case rook:
+ if ( to < A6
+ || from < A6 ) { flag_promo = 1; flag_unpromo = 0; }
+ break;
+
+ default:
+ break;
+ }
+ assert( flag_promo || flag_unpromo );
+ if ( flag_promo )
+ {
+ *pmove++ = ( From2Move(from) | To2Move(to) | FLAG_PROMO
+ | Piece2Move(pc) | Cap2Move(-BOARD[to]) );
+ }
+ if ( flag_unpromo )
+ {
+ *pmove++ = ( From2Move(from) | To2Move(to)
+ | Piece2Move(pc) | Cap2Move(-BOARD[to]) );
+ }
+ }
+ }
+
+ return pmove;
+}
+
+
+static unsigned int *
+gen_king_move( const tree_t * restrict ptree, const char *psq, int turn,
+ int is_capture, unsigned int * restrict pmove )
+{
+ bitboard_t bb;
+ int to, from;
+
+ if ( turn )
+ {
+ from = SQ_WKING;
+ bb = abb_king_attacks[from];
+ if ( is_capture )
+ {
+ BBAnd( bb, bb, BB_BOCCUPY );
+ BBNotAnd( bb, abb_mask[(int)psq[0]] );
+ }
+ else { BBNotAnd( bb, BB_BOCCUPY ); }
+ BBNotAnd( bb, BB_WOCCUPY );
+ }
+ else {
+ from = SQ_BKING;
+ bb = abb_king_attacks[from];
+ if ( is_capture )
+ {
+ BBAnd( bb, bb, BB_WOCCUPY );
+ BBNotAnd( bb, abb_mask[(int)psq[0]] );
+ }
+ else { BBNotAnd( bb, BB_WOCCUPY ); }
+ BBNotAnd( bb, BB_BOCCUPY );
+ }
+
+ while ( BBToU(bb) )
+ {
+ to = LastOne( bb );
+ Xor( to, bb );
+
+ if ( psq[1] != nsquare
+ && ( adirec[from][(int)psq[1]]
+ == adirec[from][to] ) ) { continue; }
+
+ if ( psq[0] != to
+ && adirec[from][(int)psq[0]] == adirec[from][to] ) {
+ if ( adirec[from][(int)psq[0]] & flag_cross )
+ {
+ if ( abs(BOARD[(int)psq[0]]) == lance
+ || abs(BOARD[(int)psq[0]]) == rook
+ || abs(BOARD[(int)psq[0]]) == dragon ) { continue; }
+ }
+ else if ( ( adirec[from][(int)psq[0]] & flag_diag )
+ && ( abs(BOARD[(int)psq[0]]) == bishop
+ || abs(BOARD[(int)psq[0]]) == horse ) ){ continue; }
+ }
+
+ if ( turn )
+ {
+ if ( is_white_attacked( ptree, to ) ) { continue; }
+
+ *pmove++ = ( From2Move(from) | To2Move(to)
+ | Piece2Move(king) | Cap2Move(BOARD[to]) );
+ }
+ else {
+ if ( is_black_attacked( ptree, to ) ) { continue; }
+
+ *pmove++ = ( From2Move(from) | To2Move(to)
+ | Piece2Move(king) | Cap2Move(-BOARD[to]) );
+ }
+ }
+
+ return pmove;
+}
+
+
+static unsigned int *
+gen_intercept( tree_t * restrict __ptree__, int sq_checker, int ply, int turn,
+ int * restrict premaining, unsigned int * restrict pmove,
+ int flag )
+{
+#define Drop(pc) ( To2Move(to) | Drop2Move(pc) )
+
+ const tree_t * restrict ptree = __ptree__;
+ bitboard_t bb_atk, bb_defender, bb;
+ unsigned int amove[16];
+ unsigned int hand;
+ int n0, n1, inc, pc, sq_k, to, from, direc, nmove, nsup, i, min_chuai, itemp;
+ int dist, flag_promo, flag_unpromo;
+
+ n0 = n1 = 0;
+ if ( turn )
+ {
+ sq_k = SQ_WKING;
+ bb_defender = BB_WOCCUPY;
+ BBNotAnd( bb_defender, abb_mask[sq_k] );
+ }
+ else {
+ sq_k = SQ_BKING;
+ bb_defender = BB_BOCCUPY;
+ BBNotAnd( bb_defender, abb_mask[sq_k] );
+ }
+
+ switch ( adirec[sq_k][sq_checker] )
+ {
+ case direc_rank:
+ min_chuai = ( sq_k < A8 || I2 < sq_k ) ? 2 : 4;
+ inc = 1;
+ break;
+
+ case direc_diag1:
+ min_chuai = 3;
+ inc = 8;
+ break;
+
+ case direc_file:
+ itemp = (int)aifile[sq_k];
+ min_chuai = ( itemp == file1 || itemp == file9 ) ? 2 : 4;
+ inc = 9;
+ break;
+
+ default:
+ assert( (int)adirec[sq_k][sq_checker] == direc_diag2 );
+ min_chuai = 3;
+ inc = 10;
+ }
+ if ( sq_k > sq_checker ) { inc = -inc; }
+
+ for ( dist = 1, to = sq_k + inc;
+ to != sq_checker;
+ dist += 1, to += inc ) {
+
+ assert( 0 <= to && to < nsquare && BOARD[to] == empty );
+
+ nmove = 0;
+ bb_atk = attacks_to_piece( ptree, to );
+ BBAnd( bb, bb_defender, bb_atk );
+ while ( BBToU(bb) )
+ {
+ from = LastOne( bb );
+ Xor( from, bb );
+
+ direc = (int)adirec[sq_k][from];
+ flag_promo = 0;
+ flag_unpromo = 1;
+ if ( turn )
+ {
+ if ( direc && is_pinned_on_white_king( ptree, from, direc ) )
+ {
+ continue;
+ }
+ pc = -BOARD[from];
+ switch ( pc )
+ {
+ case pawn:
+ if ( to > I4 ) { flag_promo = 1; flag_unpromo = 0; }
+ break;
+
+ case lance: case knight:
+ if ( to > I3 ) { flag_promo = 1; flag_unpromo = 0; }
+ else if ( to > I4 ) { flag_promo = 1; }
+ break;
+
+ case silver:
+ if ( to > I4 || from > I4 ) { flag_promo = 1; }
+ break;
+
+ case bishop: case rook:
+ if ( to > I4
+ || from > I4 ) { flag_promo = 1; flag_unpromo = 0; }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else {
+ if ( direc && is_pinned_on_black_king( ptree, from, direc ) )
+ {
+ continue;
+ }
+ pc = BOARD[from];
+ switch ( pc )
+ {
+ case pawn:
+ if ( to < A6 ) { flag_promo = 1; flag_unpromo = 0; }
+ break;
+
+ case lance: case knight:
+ if ( to < A7 ) { flag_promo = 1; flag_unpromo = 0; }
+ else if ( to < A6 ) { flag_promo = 1; }
+ break;
+
+ case silver:
+ if ( to < A6 || from < A6 ) { flag_promo = 1; }
+ break;
+
+ case bishop: case rook:
+ if ( to < A6
+ || from < A6 ) { flag_promo = 1; flag_unpromo = 0; }
+ break;
+
+ default:
+ break;
+ }
+ }
+ assert( flag_promo || flag_unpromo );
+ if ( flag_promo )
+ {
+ amove[nmove++] = ( From2Move(from) | To2Move(to)
+ | FLAG_PROMO | Piece2Move(pc) );
+ }
+ if ( flag_unpromo )
+ {
+ amove[nmove++] = ( From2Move(from) | To2Move(to)
+ | Piece2Move(pc) );
+ }
+ }
+
+ nsup = ( to == sq_k + inc ) ? nmove + 1 : nmove;
+ if ( nsup > 1 )
+ {
+ for ( i = n0 + n1 - 1; i >= n0; i-- ) { pmove[i+nmove] = pmove[i]; }
+ for ( i = 0; i < nmove; i++ ) { pmove[n0++] = amove[i]; }
+ }
+ else if ( nmove ) { pmove[n0 + n1++] = amove[0]; }
+
+ if ( ! nsup )
+ {
+ /* - tentative assumption - */
+ /* no recursive drops at non-supported square. */
+ if ( flag == 2 ) { continue; }
+
+ /* -tentative assumption- */
+ /* no intercept-drop at non-supported square. */
+ if ( I2To(MOVE_LAST) == sq_checker && dist > min_chuai ) { continue; }
+ }
+
+ nmove = 0;
+
+ if ( turn ) {
+
+ hand = HAND_W;
+
+ if ( nsup ) {
+
+ if ( IsHandRook(hand) ) { amove[nmove++] = Drop(rook); }
+ else if ( IsHandLance(hand) && to < A1 )
+ {
+ amove[nmove++] = Drop(lance);
+ }
+ else if ( IsHandPawn(hand)
+ && to < A1
+ && ! ( BBToU(BB_WPAWN) & ( mask_file1 >> aifile[to] ) )
+ && ! IsMateWPawnDrop( __ptree__, to ) )
+ {
+ amove[nmove++] = Drop(pawn);
+ }
+
+ } else {
+
+ if ( IsHandPawn(hand)
+ && to < A1
+ && ! ( BBToU(BB_WPAWN) & ( mask_file1 >> aifile[to] ) )
+ && ! IsMateWPawnDrop( __ptree__, to ) )
+ {
+ amove[nmove++] = Drop(pawn);
+ }
+ if ( IsHandLance(hand) && to < A1 ) { amove[nmove++] = Drop(lance); }
+ if ( IsHandRook(hand) ) { amove[nmove++] = Drop(rook); }
+ }
+
+ if ( IsHandKnight(hand) && to < A2 ) { amove[nmove++] = Drop(knight); }
+
+ } else {
+
+ hand = HAND_B;
+
+ if ( nsup ) {
+
+ if ( IsHandRook(hand) ) { amove[nmove++] = Drop(rook); }
+ else if ( IsHandLance(hand) && to > I9 )
+ {
+ amove[nmove++] = Drop(lance);
+ }
+ else if ( IsHandPawn(hand)
+ && to > I9
+ && ! ( BBToU(BB_BPAWN) & ( mask_file1 >> aifile[to] ) )
+ && ! IsMateBPawnDrop( __ptree__, to ) )
+ {
+ amove[nmove++] = Drop(pawn);
+ }
+
+ } else {
+
+ if ( IsHandPawn(hand)
+ && to > I9
+ && ! ( BBToU(BB_BPAWN) & ( mask_file1 >> aifile[to] ) )
+ && ! IsMateBPawnDrop( __ptree__, to ) )
+ {
+ amove[nmove++] = Drop(pawn);
+ }
+ if ( IsHandLance(hand) && to > I9 ) { amove[nmove++] = Drop(lance); }
+ if ( IsHandRook(hand) ) { amove[nmove++] = Drop(rook); }
+ }
+
+ if ( IsHandKnight(hand) && to > I8 ) { amove[nmove++] = Drop(knight); }
+ }
+
+ if ( IsHandSilver(hand) ) { amove[nmove++] = Drop(silver); }
+ if ( IsHandGold(hand) ) { amove[nmove++] = Drop(gold); }
+ if ( IsHandBishop(hand) ) { amove[nmove++] = Drop(bishop); }
+
+ if ( nsup )
+ {
+ /* - tentative assumption - */
+ /* a supported intercepter saves the king for two plies at least. */
+ if ( nmove && flag == 0 && dist > min_chuai
+ && I2From(MOVE_LAST) >= nsquare )
+ {
+ *premaining = -1;
+ pmove[0] = amove[0];
+ return pmove + 1;
+ }
+
+ for ( i = n0 + n1 - 1; i >= n0; i-- ) { pmove[i+nmove] = pmove[i]; }
+ for ( i = 0; i < nmove; i++ ) { pmove[n0++] = amove[i]; }
+ }
+ else for ( i = 0; i < nmove; i++ ) { pmove[n0 + n1++] = amove[i]; }
+ }
+
+ *premaining = n0;
+ return pmove + n0 + n1;
+
+#undef Drop
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+
+#define BAddMoveCap(piece) \
+ utemp = From2Move(from) | Piece2Move(piece); \
+ while ( BBToU( bb_move ) ) { \
+ to = LastOne( bb_move ); \
+ *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp; \
+ Xor( to, bb_move ); }
+
+#define BAddMove(piece) utemp = From2Move(from) | Piece2Move(piece); \
+ while ( BBToU( bb_move ) ) { \
+ to = LastOne( bb_move ); \
+ *pmove++ = To2Move(to) | utemp; \
+ Xor( to, bb_move ); }
+
+
+#define WAddMoveCap(piece) \
+ utemp = From2Move(from) | Piece2Move(piece); \
+ while ( BBToU( bb_move ) ) { \
+ to = FirstOne( bb_move ); \
+ *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp; \
+ Xor( to, bb_move ); }
+
+#define WAddMove(piece) utemp = From2Move(from) | Piece2Move(piece); \
+ while ( BBToU( bb_move ) ) { \
+ to = FirstOne( bb_move ); \
+ *pmove++ = To2Move(to) | utemp; \
+ Xor( to, bb_move ); }
+
+
+unsigned int *
+b_gen_cap_nopro_ex2( const tree_t * restrict ptree,
+ unsigned int * restrict pmove )
+{
+ int from, to;
+ unsigned int utemp, ubb_piece0, ubb_piece1, ubb_piece2, ubb_move0;
+ bitboard_t bb_target, bb_move, bb_piece;
+
+ bb_target = BB_WOCCUPY;
+
+ ubb_move0 = BB_BPAWN_ATK.p[0] & bb_target.p[0] & 0x003ffffU;
+ while( ubb_move0 )
+ {
+ to = last_one0( ubb_move0 );
+ from = to + 9;
+ *pmove++ = To2Move(to) | From2Move(from)
+ | Cap2Move(-BOARD[to]) | Piece2Move(pawn);
+ ubb_move0 ^= abb_mask[to].p[0];
+ }
+
+ ubb_piece1 = BB_BBISHOP.p[1];
+ ubb_piece2 = BB_BBISHOP.p[2];
+ while( ubb_piece1 | ubb_piece2 )
+ {
+ from = last_one12( ubb_piece1, ubb_piece2 );
+ ubb_move0 = BishopAttack0(from) & bb_target.p[0];
+ utemp = From2Move(from) | Piece2Move(bishop);
+ while ( ubb_move0 )
+ {
+ to = last_one0( ubb_move0 );
+ *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp;
+ ubb_move0 ^= abb_mask[to].p[0];
+ }
+ ubb_piece1 ^= abb_mask[from].p[1];
+ ubb_piece2 ^= abb_mask[from].p[2];
+ }
+ ubb_piece0 = BB_BBISHOP.p[0];
+ while( ubb_piece0 )
+ {
+ from = last_one0( ubb_piece0 );
+ AttackBishop( bb_move, from );
+ BBAnd( bb_move, bb_move, bb_target );
+ BAddMoveCap( bishop );
+ ubb_piece0 ^= abb_mask[from].p[0];
+ }
+
+ ubb_piece1 = BB_BROOK.p[1];
+ ubb_piece2 = BB_BROOK.p[2];
+ while( ubb_piece1 | ubb_piece2 )
+ {
+ from = last_one12( ubb_piece1, ubb_piece2 );
+ AttackRook( bb_move, from );
+ ubb_move0 = bb_move.p[0] & bb_target.p[0];
+ utemp = From2Move(from) | Piece2Move(rook);
+ while ( ubb_move0 )
+ {
+ to = last_one0( ubb_move0 );
+ *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp;
+ ubb_move0 ^= abb_mask[to].p[0];
+ }
+ ubb_piece1 ^= abb_mask[from].p[1];
+ ubb_piece2 ^= abb_mask[from].p[2];
+ }
+ ubb_piece0 = BB_BROOK.p[0];
+ while( ubb_piece0 )
+ {
+ from = last_one0( ubb_piece0 );
+ AttackRook( bb_move, from );
+ BBAnd( bb_move, bb_move, bb_target );
+ BAddMoveCap( rook );
+ ubb_piece0 ^= abb_mask[from].p[0];
+ }
+
+ bb_piece = BB_BLANCE;
+ bb_target.p[0] &= 0x3fe00;
+ while( BBToU( bb_piece ) )
+ {
+ from = LastOne( bb_piece );
+ ubb_move0 = AttackFile(from).p[0]
+ & abb_minus_rays[from].p[0] & bb_target.p[0];
+ utemp = From2Move(from) | Piece2Move(lance);
+ while ( ubb_move0 )
+ {
+ to = last_one0( ubb_move0 );
+ *pmove++ = To2Move(to) | Cap2Move(-BOARD[to]) | utemp;
+ ubb_move0 ^= abb_mask[to].p[0];
+ }
+ Xor( from, bb_piece );
+ }
+
+ return pmove;
+}
+
+
+unsigned int *
+b_gen_nocap_nopro_ex2( const tree_t * restrict ptree,
+ unsigned int * restrict pmove )
+{
+ bitboard_t bb_target, bb_move, bb_piece;
+ unsigned int ubb_piece0, ubb_piece1, ubb_piece2, ubb_move0, ubb_target0;
+ unsigned int utemp;
+ int to, from;
+
+ BBOr( bb_target, BB_BOCCUPY, BB_WOCCUPY );
+ BBNot( bb_target, bb_target );
+
+ ubb_move0 = BB_BPAWN_ATK.p[0] & bb_target.p[0] & 0x003ffffU;
+ while( ubb_move0 )
+ {
+ to = last_one0( ubb_move0 );
+ from = to + 9;
+ *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(pawn);
+ ubb_move0 ^= abb_mask[to].p[0];
+ }
+
+ ubb_piece1 = BB_BBISHOP.p[1];
+ ubb_piece2 = BB_BBISHOP.p[2];
+ while( ubb_piece1 | ubb_piece2 )
+ {
+ from = last_one12( ubb_piece1, ubb_piece2 );
+ ubb_move0 = BishopAttack0(from) & bb_target.p[0];
+ utemp = From2Move(from) | Piece2Move(bishop);
+ while ( ubb_move0 )
+ {
+ to = last_one0( ubb_move0 );
+ *pmove++ = To2Move(to) | utemp;
+ ubb_move0 ^= abb_mask[to].p[0];
+ }
+ ubb_piece1 ^= abb_mask[from].p[1];
+ ubb_piece2 ^= abb_mask[from].p[2];
+ }
+ ubb_piece0 = BB_BBISHOP.p[0];
+ while( ubb_piece0 )
+ {
+ from = last_one0( ubb_piece0 );
+ AttackBishop( bb_move, from );
+ BBAnd( bb_move, bb_move, bb_target );
+ BAddMove( bishop );
+ ubb_piece0 ^= abb_mask[from].p[0];
+ }
+
+ ubb_piece1 = BB_BROOK.p[1];
+ ubb_piece2 = BB_BROOK.p[2];
+ while( ubb_piece1 | ubb_piece2 )
+ {
+ from = last_one12( ubb_piece1, ubb_piece2 );
+ AttackRook( bb_move, from );
+ ubb_move0 = bb_move.p[0] & bb_target.p[0];
+ utemp = From2Move(from) | Piece2Move(rook);
+ while ( ubb_move0 )
+ {
+ to = last_one0( ubb_move0 );
+ *pmove++ = To2Move(to) | utemp;
+ ubb_move0 ^= abb_mask[to].p[0];
+ }
+ ubb_piece1 ^= abb_mask[from].p[1];
+ ubb_piece2 ^= abb_mask[from].p[2];
+ }
+ ubb_piece0 = BB_BROOK.p[0];
+ while( ubb_piece0 )
+ {
+ from = last_one0( ubb_piece0 );
+ AttackRook( bb_move, from );
+ BBAnd( bb_move, bb_move, bb_target );
+ BAddMove( rook );
+ ubb_piece0 ^= abb_mask[from].p[0];
+ }
+
+ bb_piece = BB_BLANCE;
+ ubb_target0 = bb_target.p[0] & 0x3fe00;
+ while( BBToU( bb_piece ) )
+ {
+ from = LastOne( bb_piece );
+ ubb_move0 = AttackFile(from).p[0]
+ & abb_minus_rays[from].p[0] & ubb_target0;
+ utemp = From2Move(from) | Piece2Move(lance);
+ while ( ubb_move0 )
+ {
+ to = last_one0( ubb_move0 );
+ *pmove++ = To2Move(to) | utemp;
+ ubb_move0 ^= abb_mask[to].p[0];
+ }
+ Xor( from, bb_piece );
+ }
+
+ return pmove;
+}
+
+
+unsigned int *
+w_gen_cap_nopro_ex2( const tree_t * restrict ptree,
+ unsigned int * restrict pmove )
+{
+ bitboard_t bb_target, bb_move, bb_piece;
+ unsigned int utemp, ubb_piece0, ubb_piece1, ubb_piece2, ubb_move2;
+ int from, to;
+
+ bb_target = BB_BOCCUPY;
+
+ ubb_move2 = BB_WPAWN_ATK.p[2] & bb_target.p[2] & 0x7fffe00U;
+ while( ubb_move2 )
+ {
+ to = first_one2( ubb_move2 );
+ from = to - 9;
+ *pmove++ = To2Move(to) | From2Move(from)
+ | Cap2Move(BOARD[to]) | Piece2Move(pawn);
+ ubb_move2 ^= abb_mask[to].p[2];
+ }
+
+ ubb_piece0 = BB_WBISHOP.p[0];
+ ubb_piece1 = BB_WBISHOP.p[1];
+ while( ubb_piece0 | ubb_piece1 )
+ {
+ from = first_one01( ubb_piece0, ubb_piece1 );
+ ubb_move2 = BishopAttack2(from) & bb_target.p[2];
+ utemp = From2Move(from) | Piece2Move(bishop);
+ while ( ubb_move2 )
+ {
+ to = first_one2( ubb_move2 );
+ *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp;
+ ubb_move2 ^= abb_mask[to].p[2];
+ }
+ ubb_piece0 ^= abb_mask[from].p[0];
+ ubb_piece1 ^= abb_mask[from].p[1];
+ }
+ ubb_piece2 = BB_WBISHOP.p[2];
+ while( ubb_piece2 )
+ {
+ from = first_one2( ubb_piece2 );
+ AttackBishop( bb_move, from );
+ BBAnd( bb_move, bb_move, bb_target );
+ WAddMoveCap( bishop );
+ ubb_piece2 ^= abb_mask[from].p[2];
+ }
+
+ ubb_piece0 = BB_WROOK.p[0];
+ ubb_piece1 = BB_WROOK.p[1];
+ while( ubb_piece0 | ubb_piece1 )
+ {
+ from = first_one01( ubb_piece0, ubb_piece1 );
+ AttackRook( bb_move, from );
+ ubb_move2 = bb_move.p[2] & bb_target.p[2];
+ utemp = From2Move(from) | Piece2Move(rook);
+ while ( ubb_move2 )
+ {
+ to = first_one2( ubb_move2 );
+ *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp;
+ ubb_move2 ^= abb_mask[to].p[2];
+ }
+ ubb_piece0 ^= abb_mask[from].p[0];
+ ubb_piece1 ^= abb_mask[from].p[1];
+ }
+ ubb_piece2 = BB_WROOK.p[2];
+ while( ubb_piece2 )
+ {
+ from = first_one2( ubb_piece2 );
+ AttackRook( bb_move, from );
+ BBAnd( bb_move, bb_move, bb_target );
+ WAddMoveCap( rook );
+ ubb_piece2 ^= abb_mask[from].p[2];
+ }
+
+ bb_piece = BB_WLANCE;
+ bb_target.p[2] &= 0x3fe00;
+ while( BBToU( bb_piece ) )
+ {
+ from = FirstOne( bb_piece );
+ ubb_move2 = AttackFile(from).p[2]
+ & abb_plus_rays[from].p[2] & bb_target.p[2];
+ utemp = From2Move(from) | Piece2Move(lance);
+ while ( ubb_move2 )
+ {
+ to = first_one2( ubb_move2 );
+ *pmove++ = To2Move(to) | Cap2Move(BOARD[to]) | utemp;
+ ubb_move2 ^= abb_mask[to].p[2];
+ }
+ Xor( from, bb_piece );
+ }
+
+ return pmove;
+}
+
+
+unsigned int *
+w_gen_nocap_nopro_ex2( const tree_t * restrict ptree,
+ unsigned int * restrict pmove )
+{
+ bitboard_t bb_target, bb_piece, bb_move;
+ unsigned int ubb_piece0, ubb_piece1, ubb_piece2, ubb_move2, ubb_target2;
+ unsigned int utemp;
+ int to, from;
+
+ BBOr( bb_target, BB_BOCCUPY, BB_WOCCUPY );
+ BBNot( bb_target, bb_target );
+
+ ubb_move2 = BB_WPAWN_ATK.p[2] & bb_target.p[2] & 0x7fffe00U;;
+ while( ubb_move2 )
+ {
+ to = first_one2( ubb_move2 );
+ from = to - 9;
+ *pmove++ = To2Move(to) | From2Move(from) | Piece2Move(pawn);
+ ubb_move2 ^= abb_mask[to].p[2];
+ }
+
+ ubb_piece0 = BB_WBISHOP.p[0];
+ ubb_piece1 = BB_WBISHOP.p[1];
+ while( ubb_piece0 | ubb_piece1 )
+ {
+ from = first_one01( ubb_piece0, ubb_piece1 );
+ ubb_move2 = BishopAttack2(from) & bb_target.p[2];
+ utemp = From2Move(from) | Piece2Move(bishop);
+ while ( ubb_move2 )
+ {
+ to = first_one2( ubb_move2 );
+ *pmove++ = To2Move(to) | utemp;
+ ubb_move2 ^= abb_mask[to].p[2];
+ }
+ ubb_piece0 ^= abb_mask[from].p[0];
+ ubb_piece1 ^= abb_mask[from].p[1];
+ }
+ ubb_piece2 = BB_WBISHOP.p[2];
+ while( ubb_piece2 )
+ {
+ from = first_one2( ubb_piece2 );
+ AttackBishop( bb_move, from );
+ BBAnd( bb_move, bb_move, bb_target );
+ WAddMove( bishop );
+ ubb_piece2 ^= abb_mask[from].p[2];
+ }
+
+ ubb_piece0 = BB_WROOK.p[0];
+ ubb_piece1 = BB_WROOK.p[1];
+ while( ubb_piece0 | ubb_piece1 )
+ {
+ from = first_one01( ubb_piece0, ubb_piece1 );
+ AttackRook( bb_move, from );
+ ubb_move2 = bb_move.p[2] & bb_target.p[2];
+ utemp = From2Move(from) | Piece2Move(rook);
+ while ( ubb_move2 )
+ {
+ to = first_one2( ubb_move2 );
+ *pmove++ = To2Move(to) | utemp;
+ ubb_move2 ^= abb_mask[to].p[2];
+ }
+ ubb_piece0 ^= abb_mask[from].p[0];
+ ubb_piece1 ^= abb_mask[from].p[1];
+ }
+ ubb_piece2 = BB_WROOK.p[2];
+ while( ubb_piece2 )
+ {
+ from = first_one2( ubb_piece2 );
+ AttackRook( bb_move, from );
+ BBAnd( bb_move, bb_move, bb_target );
+ WAddMove( rook );
+ ubb_piece2 ^= abb_mask[from].p[2];
+ }
+
+ bb_piece = BB_WLANCE;
+ ubb_target2 = bb_target.p[2] & 0x3fe00;
+ while( BBToU( bb_piece ) )
+ {
+ from = FirstOne( bb_piece );
+ ubb_move2 = AttackFile(from).p[2]
+ & abb_plus_rays[from].p[2] & ubb_target2;
+ utemp = From2Move(from) | Piece2Move(lance);
+ while ( ubb_move2 )
+ {
+ to = first_one2( ubb_move2 );
+ *pmove++ = To2Move(to) | utemp;
+ ubb_move2 ^= abb_mask[to].p[2];
+ }
+ Xor( from, bb_piece );
+ }
+
+ return pmove;
+}
+
+
+#undef BAddMoveCap
+#undef BAddMove
+#undef WAddMoveCap
+#undef WAddMove
--- /dev/null
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include "shogi.h"
+
+int
+gen_next_move( tree_t * restrict ptree, int ply, int turn )
+{
+ switch ( ptree->anext_move[ply].next_phase )
+ {
+ case next_move_hash:
+ {
+ unsigned int * restrict pmove;
+ int * restrict psortv = ptree->sort_value;
+ unsigned int move, killer1, killer2, move_hash, move_best, move_second;
+ int i, j, sortv, n, value_best, value_second, value, remaining;
+
+ ptree->anext_move[ply].phase_done = 0;
+ ptree->anext_move[ply].next_phase = next_move_capture;
+ ptree->anext_move[ply].move_last = pmove = ptree->move_last[ply];
+ ptree->move_last[ply] = GenCaptures( turn, pmove );
+
+ move_hash = ptree->amove_hash[ply];
+ killer1 = ptree->amove_killer[ply].no1;
+ killer2 = ptree->amove_killer[ply].no2;
+ remaining = 0;
+ move_best = move_second = 0;
+ value_best = value_second = 0;
+ n = (int)( ptree->move_last[ply] - pmove );
+ for ( i = 0; i < n; i++ )
+ {
+ move = pmove[i];
+ sortv = swap( ptree, move, -1, INT_MAX, turn );
+ if ( sortv > value_best )
+ {
+ move_second = move_best;
+ value_second = value_best;
+ value_best = sortv;
+ move_best = move;
+ }
+ else if ( sortv > value_second )
+ {
+ move_second = move;
+ value_second = sortv;
+ }
+ if ( move == move_hash ) { sortv = INT_MIN; }
+ else if ( UToFromToPromo(move) == killer1 )
+ {
+ killer1 = 0;
+ value = ptree->amove_killer[ply].no1_value
+ + p_value_ex[15U+UToCap(move)];
+ if ( sortv < value ) { sortv = value; }
+ if ( sortv > -1 ) { remaining++; }
+ }
+ else if ( UToFromToPromo(move) == killer2 )
+ {
+ killer2 = 0;
+ value = ptree->amove_killer[ply].no2_value
+ + p_value_ex[15U+UToCap(move)];
+ if ( sortv < value ) { sortv = value; }
+ if ( sortv > -1 ) { remaining++; }
+ }
+ else if ( sortv > -1 ) { remaining++; }
+ psortv[i] = sortv;
+ }
+
+ if ( killer1
+ && killer1 != move_hash
+ && ptree->amove_killer[ply].no1_value > -1
+ && is_move_valid( ptree, killer1, turn ) )
+ {
+ *( ptree->move_last[ply]++ ) = killer1;
+ psortv[n++] = ptree->amove_killer[ply].no1_value;
+ remaining++;
+ }
+
+ if ( killer2
+ && killer2 != move_hash
+ && ptree->amove_killer[ply].no2_value > -1
+ && is_move_valid( ptree, killer2, turn ) )
+ {
+ *( ptree->move_last[ply]++ ) = killer2;
+ psortv[n++] = ptree->amove_killer[ply].no2_value;
+ remaining++;
+ }
+
+ ptree->anext_move[ply].value_cap1 = value_best;
+ ptree->anext_move[ply].move_cap1 = move_best;
+ ptree->anext_move[ply].value_cap2 = value_second;
+ ptree->anext_move[ply].move_cap2 = move_second;
+ ptree->anext_move[ply].remaining = remaining;
+
+ /* insertion sort */
+ psortv[n] = INT_MIN;
+ for ( i = n-2; i >= 0; i-- )
+ {
+ sortv = psortv[i]; move = pmove[i];
+ for ( j = i+1; psortv[j] > sortv; j++ )
+ {
+ psortv[j-1] = psortv[j]; pmove[j-1] = pmove[j];
+ }
+ psortv[j-1] = sortv; pmove[j-1] = move;
+ }
+ if ( psortv[n-1] == INT_MIN ) { ptree->move_last[ply]--; }
+
+#if ! defined(MINIMUM)
+ if ( move_hash && ! is_move_valid( ptree, move_hash, turn ) )
+ {
+ out_warning( "An invalid hash move is found!!" );
+ ptree->amove_hash[ply] = move_hash = 0U;
+ }
+#endif
+
+ if ( move_hash )
+ {
+ if ( move_hash == move_best )
+ {
+ ptree->anext_move[ply].phase_done |= phase_cap1;
+ }
+
+ if ( UToFromToPromo(move_hash) == killer1 )
+ {
+ ptree->anext_move[ply].phase_done |= phase_killer1;
+ }
+ else if ( UToFromToPromo(move_hash) == killer2 )
+ {
+ ptree->anext_move[ply].phase_done |= phase_killer2;
+ }
+ ptree->anext_move[ply].phase_done |= phase_hash;
+ MOVE_CURR = move_hash;
+ return 1;
+ }
+ }
+
+ case next_move_capture:
+ if ( ptree->anext_move[ply].remaining-- )
+ {
+ unsigned int move;
+
+ MOVE_CURR = move = *(ptree->anext_move[ply].move_last++);
+ if ( move == ptree->anext_move[ply].move_cap1 )
+ {
+ ptree->anext_move[ply].phase_done |= phase_cap1;
+ }
+
+ if ( UToFromToPromo(move) == ptree->amove_killer[ply].no1 )
+ {
+ ptree->anext_move[ply].phase_done |= phase_killer1;
+ }
+ else if ( UToFromToPromo(move) == ptree->amove_killer[ply].no2 )
+ {
+ ptree->anext_move[ply].phase_done |= phase_killer2;
+ }
+ return 1;
+ }
+
+ {
+ unsigned int * restrict pmove;
+ unsigned int value_best, value, key, good, tried;
+ int i, n, ibest;
+
+ value_best = 0;
+ ibest = -1;
+ ptree->move_last[ply] = GenNoCaptures( turn, ptree->move_last[ply] );
+ ptree->move_last[ply] = GenDrop( turn, ptree->move_last[ply] );
+ n = (int)( ptree->move_last[ply] - ptree->anext_move[ply].move_last );
+ pmove = ptree->anext_move[ply].move_last;
+ for ( i = 0; i < n; i++ )
+ {
+ if ( pmove[i] == ptree->amove_hash[ply]
+ || ( pmove[i] == ptree->amove_killer[ply].no1
+ && ( ptree->anext_move[ply].phase_done
+ & phase_killer1 ) )
+ || ( pmove[i] == ptree->amove_killer[ply].no2
+ && ( ptree->anext_move[ply].phase_done
+ & phase_killer2 ) ) )
+ {
+ pmove[i] = 0;
+ continue;
+ }
+
+ if ( UToCap(pmove[i]) ) { continue; }
+ if ( I2IsPromote(pmove[i])
+ && I2PieceMove(pmove[i]) != silver ) { continue; }
+
+
+ key = phash( pmove[i], turn );
+ good = ptree->hist_good[key] + 1;
+ tried = ptree->hist_tried[key] + 2;
+ value = ( good * 8192U ) / tried;
+ if ( value > value_best )
+ {
+ value_best = value;
+ ibest = i;
+ }
+ }
+
+ if ( ibest >= 0 )
+ {
+ ptree->anext_move[ply].phase_done |= phase_history1;
+ ptree->anext_move[ply].next_phase = next_move_history2;
+ MOVE_CURR = pmove[ibest];
+ pmove[ibest] = 0;
+ return 1;
+ }
+ }
+
+ case next_move_history2:
+ {
+ unsigned int * restrict pmove;
+ unsigned int value_best, value, key, good, tried;
+ int ibest, i, n;
+
+ ptree->anext_move[ply].next_phase = next_move_misc;
+ value_best = 0;
+ ibest = -1;
+ n = (int)( ptree->move_last[ply] - ptree->anext_move[ply].move_last );
+ pmove = ptree->anext_move[ply].move_last;
+
+ for ( i = 0; i < n; i++ )
+ {
+ if ( UToCap(pmove[i]) ) { continue; }
+ if ( I2IsPromote(pmove[i])
+ && I2PieceMove(pmove[i]) != silver ) { continue; }
+
+ key = phash( pmove[i], turn );
+ good = ptree->hist_good[key] + 1;
+ tried = ptree->hist_tried[key] + 2;
+ value = ( good * 8192U ) / tried;
+ if ( value > value_best && pmove[i] )
+ {
+ value_best = value;
+ ibest = i;
+ }
+ }
+
+ if ( ibest >= 0 )
+ {
+ ptree->anext_move[ply].phase_done |= phase_history2;
+ MOVE_CURR = pmove[ibest];
+ pmove[ibest] = 0;
+ return 1;
+ }
+ }
+
+ default:
+ assert( ptree->anext_move[ply].next_phase == next_move_misc );
+ while ( ptree->anext_move[ply].move_last < ptree->move_last[ply] )
+ {
+ if ( *( ptree->anext_move[ply].move_last ) )
+ {
+ MOVE_CURR = *(ptree->anext_move[ply].move_last++);
+ ptree->anext_move[ply].phase_done |= phase_misc;
+ return 1;
+ }
+ ptree->anext_move[ply].move_last++;
+ }
+ }
+ return 0;
+}
+
+
+int
+gen_next_evasion( tree_t * restrict ptree, int ply, int turn )
+{
+ switch ( ptree->anext_move[ply].next_phase )
+ {
+ case next_evasion_hash:
+ ptree->move_last[ply] = GenEvasion( turn, ptree->move_last[ply] );
+
+ if ( ptree->amove_hash[ply] )
+ {
+#if ! defined(MINIMUM)
+ unsigned int * restrict p;
+
+ for ( p = ptree->move_last[ply-1]; p < ptree->move_last[ply]; p++ )
+ if ( *p == ptree->amove_hash[ply] ) { break; }
+
+ if ( *p != ptree->amove_hash[ply] )
+ {
+ out_warning( "An invalid hash evasion-move is found!!" );
+ out_board( ptree, stdout, 0, 0 );
+ Out( "%c%s\n", ach_turn[turn],
+ str_CSA_move(ptree->amove_hash[ply]) );
+ Out( "hash key = %" PRIu64 ", hand = %u, turn = %d\n",
+ HASH_KEY, HAND_B, turn );
+ ptree->amove_hash[ply] = 0U;
+ }
+ else
+#endif
+ {
+ ptree->anext_move[ply].next_phase = next_evasion_genall;
+ ptree->current_move[ply] = ptree->amove_hash[ply];
+ return 1;
+ }
+ }
+
+ case next_evasion_genall:
+ {
+ unsigned int * restrict pmove;
+ int * restrict psortv;
+ unsigned int move;
+ int n, i, j, sortv;
+
+ ptree->anext_move[ply].next_phase = next_evasion_misc;
+ ptree->anext_move[ply].move_last = pmove = ptree->move_last[ply-1];
+ n = (int)( ptree->move_last[ply] - pmove );
+ psortv = ptree->sort_value;
+
+ for ( i = n-1; i >= 0; i-- )
+ {
+ move = pmove[i];
+ if ( move == ptree->amove_hash[ply] )
+ {
+ sortv = INT_MIN;
+ pmove[i] = 0;
+ }
+ else if ( I2PieceMove(move) == king )
+ {
+ sortv = p_value_ex[UToCap(move)+15] * 2;
+ }
+ else {
+ sortv = swap( ptree, move, INT_MIN, INT_MAX, turn );
+ sortv += estimate_score_diff( ptree, move, turn );
+ }
+ psortv[i] = sortv;
+ }
+
+ /* insertion sort */
+ psortv[n] = INT_MIN;
+ for ( i = n-2; i >= 0; i-- )
+ {
+ sortv = psortv[i]; move = pmove[i];
+ for ( j = i+1; psortv[j] > sortv; j++ )
+ {
+ psortv[j-1] = psortv[j]; pmove[j-1] = pmove[j];
+ }
+ psortv[j-1] = sortv; pmove[j-1] = move;
+ }
+ }
+
+ default:
+ assert( ptree->anext_move[ply].next_phase == next_evasion_misc );
+ while ( ptree->anext_move[ply].move_last < ptree->move_last[ply] )
+ {
+ if ( *( ptree->anext_move[ply].move_last ) )
+ {
+ ptree->current_move[ply] = *(ptree->anext_move[ply].move_last++);
+ return 1;
+ }
+ ptree->anext_move[ply].move_last++;
+ }
+ }
+ return 0;
+}
--- /dev/null
+#define DPawn 87 /* 174 */
+#define DLance 235 /* 470 */
+#define DKnight 254 /* 508 */
+#define DProPawn 530 /* 617 */
+#define DProLance 482 /* 717 */
+#define DSilver 371 /* 742 */
+#define DProKnight 500 /* 754 */
+#define DProSilver 489 /* 860 */
+#define DGold 447 /* 894 */
+#define DBishop 571 /* 1142 */
+#define DRook 647 /* 1294 */
+#define DHorse 832 /* 1403 */
+#define DDragon 955 /* 1602 */
+#define DKing 15000
+
--- /dev/null
+#include "shogi.h"\r
+\r
+static unsigned short tab[] = {\r
+5866,14081,15663,4534,14969,3034,8274,7570,\r
+14571,15428,2921,37,2534,4727,660,249,\r
+8308,3662,15794,10079,13857,13019,6070,9141,\r
+3942,14629,6891,11561,12156,4793,11132,12989,\r
+10044,16304,9389,2228,5053,3789,5988,4479,\r
+8719,13901,15524,3098,7570,12949,1074,0,\r
+10079,16233,7531,14642,13600,8087,0,11690,\r
+8579,15413,6522,1076,2677,6914,10881,13803,\r
+13806,15789,14642,2135,15427,14023,14079,7708,\r
+3602,0,4976,10910,4821,4543,5455,9368,\r
+4201,9970,10647,15130,10079,15020,5558,15902,\r
+7858,2962,10386,2155,14641,12308,8021,8170,\r
+2490,10528,15427,14629,10528,15136,999,1883,\r
+14912,10788,6360,3677,14960,12257,2294,12614,\r
+8698,12433,9867,12663,16016,11332,8568,8348,\r
+0,3228,8594,11249,6674,3098,9297,10077,\r
+10340,5803,5420,6070,660,5676,1,9497,\r
+8700,14264,5846,12433,16282,12561,12032,13732,\r
+8239,10731,7236,10286,2678,7321,13368,6594,\r
+9047,5291,8293,2809,3268,6485,10509,2277,\r
+10471,595,8887,15919,14413,15881,8827,13726,\r
+13975,14092,7634,1652,8753,6801,6568,15853,\r
+1022,5664,0,9303,15719,6128,6674,7433,\r
+157,9360,6555,12432,9593,9660,14081,13927,\r
+8702,13702,8663,5629,3691,16298,1573,902,\r
+1272,2376,1084,14447,14666,1692,15316,15129,\r
+3833,920,8348,15839,15902,15635,10340,6603,\r
+1764,9634,3833,2470,4704,9646,385,13200,\r
+3009,1562,6846,6598,15861,8924,11762,3766,\r
+9095,431,6599,1987,15902,11064,4972,12175,\r
+14642,13857,6130,5833,13857,12112,8170,9867,\r
+2569,9648,1883,10205,12365,6801,5222,14506,\r
+1819,5142,2172,5291,15542,12112,2092,5560,\r
+4538,5461,15059,11773,15884,2099,6876,11914,\r
+3833,4972,8164,6240,12487,1341,10731,11762,\r
+14548,4471,5044,7576,2392,16129,8175,7559,\r
+12559,15861,6396,2926,7618,8417,15759,0,\r
+9095,3510,7247,1712,16345,2209,8055,0,\r
+319,12209,13144,15159,8238,7822,5014,10077,\r
+2284,7177,6555,15861,14479,2510,8170,11806,\r
+12149,12440,14185,11762,11552,8260,11864,11728,\r
+15046,11561,4707,13420,3615,2233,2277,10668,\r
+2228,8016,1813,2677,5240,6594,6636,9911,\r
+1737,4396,12500,9682,7176,2027,12500,5244,\r
+12112,1768,14571,12663,6729,3662,8170,15641,\r
+15316,9648,5373,5475,6522,14571,3662,15902,\r
+1652,9648,2228,8348,902,5988,9150,13250,\r
+13411,4675,431,5507,10616,13987,15316,1378,\r
+13832,13356,10087,9543,9093,8065,10497,8228,\r
+11762,616,12968,5411,9648,12487,9463,15597,\r
+11292,13985,14482,14600,1705,4678,12020,8828,\r
+6210,9481,14980,5738,5990,14447,1569,8618,\r
+2273,8543,1819,16158,12447,12470,10160,4725,\r
+10778,1412,8040,4300,9550,568,7394,592,\r
+9481,15680,3476,16128,7660,1214,359,6181,\r
+8618,4067,14699,13368,514,11355,8914,3801,\r
+14520,8885,10434,8274,7709,4312,7243,12633,\r
+4867,5981,4538,2490,3034,5558,6801,7512,\r
+14971,4315,4905,11682,8845,3732,1475,11661,\r
+10189,1741,11667,5605,2656,9573,10898,2796,\r
+1817,15216,11152,470,5988,6164,4972,10386,\r
+13128,7247,3268,6729,4300,13101,8568,12663,\r
+13849,3600,9718,11203,10528,13732,5251,14148,\r
+8568,13128,10205,11332,1712,12821,9557,12753,\r
+10505,5276,109,10394,10122,9809,3513,16093,\r
+2490,9943,14798,15084,4598,5174,15648,13109,\r
+0,6971,15426,14500,14571,6831,2623,6801,\r
+6522,15388,3228,11053,0,2902,4285,13853,\r
+14830,5373,15137,10087,3268,2569,6284,2902,\r
+1483,3838,12159,4764,15130,6846,6957,12499,\r
+4604,2739,14629,996,4867,13420,7791,5263,\r
+8119,10088,4128,7950,11875,16244,1147,3473,\r
+3268,15869,12821,11152,9922,1987,8238,15271,\r
+852,6921,4155,7857,11187,2275,14224,15725,\r
+9967,4479,6522,11152,2457,5962,13732,10088,\r
+11226,11359,5053,13420,3727,12487,3823,13412,\r
+13732,5962,11005,11173,8719,4354,6821,11421,\r
+15640,4769,14868,9369,215,8176,2363,1930,\r
+4124,11338,5373,2135,5253,10648,6220,5853,\r
+2741,12020,14070,14571,7476,9011,11415,1306,\r
+5318,13418,7293,15364,8898,3402,11976,9325,\r
+1562,7366,3395,10762,7144,2336,13458,4538,\r
+1159,1987,11652,12964,13513,541,13792,9741,\r
+10840,16129,10917,4534,13600,5462,2357,3890,\r
+6299,11315,13376,13820,13369,4450,14282,3510,\r
+10008,2381,9301,10165,4832,13042,3789,11751,\r
+8021,14286,9341,436,9171,8623,12745,12738,\r
+567,13996,3654,9495,844,8260,15108,2851,\r
+10351,2756,8572,3694,8851,5833,4280,12168,\r
+9550,9095,1652,6594,2534,3662,12009,6827,\r
+7447,2228,6555,15919,2294,6522,6674,0,\r
+13128,15478,3098,14571,1573,13117,16336,3422,\r
+12751,4635,9808,13171,11875,14148,14759,15680,\r
+610,780,14127,15067,12717,11768,2223,4745,\r
+2111,4363,6821,12230,13200,16093,410,15205,\r
+3838,15020,12230,3473,7951,2926,981,13414,\r
+3034,9835,3875,7247,15776,11053,10533,6393,\r
+6729,1712,12233,10088,5152,1378,6043,3871,\r
+6043,12487,15527,11769,12308,5962,11864,10804,\r
+3268,14005,13662,10647,4972,15137,14485,7784,\r
+7275,410,6555,2470,7074,359,12751,12054,\r
+8851,2993,9487,13270,9267,2370,8119,14112,\r
+6639,157,10245,16121,9967,14912,10307,8011,\r
+12094,2470,10322,3570,6154,1453,15084,14801,\r
+3823,7259,780,4972,13047,14500,2569,5833,\r
+56,14601,2690,5036,788,46,2738,9922,\r
+11332,10619,8011,13128,3268,431,13412,8851,\r
+14748,5036,12185,13042,10030,11716,100,16205,\r
+7951,5738,8417,10757,6463,7114,1183,14798,\r
+10205,9721,15359,10074,8727,4587,11875,14615,\r
+10340,9171,9171,4686,7731,4269,13042,8574,\r
+16298,7024,10309,2858,4904,7223,8238,7512,\r
+4556,3532,15222,2161,1162,6476,3221,10290,\r
+11229,15137,14921,1319,4925,1991,7817,7427,\r
+15089,9366,920,3875,4641,11787,14255,4915,\r
+7588,15555,13106,16014,12882,10324,341,1331,\r
+10685,7950,12292,10230,15336,7431,7576,6158,\r
+5058,12149,2777,13434,5263,15769,9877,2704,\r
+10300,867,1443,5285,2155,4474,935,12586,\r
+12601,158,16191,8119,3726,3554,10398,13418,\r
+8170,4867,14642,15478,1712,10136,6674,0,\r
+46,9867,3766,12433,6057,3972,2156,852,\r
+2144,9856,14761,11491,46,363,10561,4484,\r
+999,9557,2902,7323,15084,8274,16087,6679,\r
+6867,6971,2914,586,6240,5988,10386,8304,\r
+3662,10088,5988,12821,7409,8308,15931,14376,\r
+14700,15998,4484,1766,15794,3833,2464,4342,\r
+1358,319,10099,15776,15839,1530,8538,7800,\r
+3641,5569,7469,2104,8314,8976,5962,11857,\r
+10330,8293,12356,1399,1991,5415,10497,15478,\r
+15931,8308,11608,10167,4185,9369,1658,6193,\r
+5962,5132,12322,319,7802,4707,3034,11308,\r
+9559,10788,2228,8339,13513,5222,1712,3098,\r
+1987,2719,1548,15427,13361,13736,5139,1255,\r
+11064,8011,985,6135,788,2761,6522,5362,\r
+13128,3476,6164,12032,2902,15881,11053,14538,\r
+12964,14730,3751,12890,396,1132,6164,7938,\r
+3165,7677,12218,7007,4824,6266,4198,9127,\r
+12821,6463,199,6522,5462,1084,7232,15717,\r
+3354,2788,6294,11857,14174,2235,6135,7808,\r
+15931,10377,1168,9162,7176,3595,10046,1960,\r
+3726,1723,6779,10955,11201,4721,661,7247,\r
+5988,11291,9095,8555,7017,5975,14500,15822,\r
+10887,7999,9648,15908,2938,8293,14629,4233,\r
+8419,5141,12427,9360,2948,9321,13473,1134,\r
+87,4180,2284,8822,3893,15653,15668,12175,\r
+7951,12668,13119,7839,4793,4686,914,9481,\r
+11912,13196,4235,15293,5704,9063,1605,15640,\r
+13270,1192,9967,8698,5576,3059,4067,11809,\r
+5420,7691,16087,764,12487,2273,14224,13412,\r
+5373,12663,788,12433,8870,15902,14019,3966,\r
+1104,11153,13117,8913,46,9922,15240,8260,\r
+9874,1712,9096,7708,4544,15601,0,10529,\r
+7419,9404,653,4067,10717,4901,10009,7229,\r
+9867,7620,1412,14284,9931,8845,13975,8238,\r
+10941,10205,678,11308,14985,12099,3268,11120,\r
+14148,7900,5934,10099,12903,6274,9648,2851,\r
+972,5149,9506,12102,723,15873,14497,5447,\r
+13505,13658,13128,4699,11152,0,0,7808,\r
+2623,6674,9557,7920,10004,14081,0,15478,\r
+12498,7162,13662,14438,6939,10841,6599,7074,\r
+2129,9303,3614,5121,13626,14806,13096,5275,\r
+12032,11431,12265,242,12651,6465,11153,15635,\r
+6154,7864,3263,7708,13216,9466,4929,4763,\r
+16121,12949,6801,14244,6289,3766,8913,3228,\r
+10099,4198,11895,286,13119,10778,12230,7238,\r
+3614,14081,7323,4050,6846,14629,13420,9427,\r
+5460,5130,10528,15705,6369,8361,1212,8866,\r
+12821,15427,7323,2777,9648,8744,5386,8241,\r
+11875,14112,14770,15369,9813,6750,13732,6594,\r
+2464,11682,2031,15129,3532,12112,4831,4354,\r
+2275,10376,11226,11611,8313,9590,14500,8598,\r
+13403,4316,15388,13458,961,208,5995,1225,\r
+6455,5932,11987,2902,13128,1224,1003,7409,\r
+3028,650,13436,8485,6653,911,9425,11421,\r
+9554,10993,15293,514,6670,14578,4972,9874,\r
+8483,2534,14969,1934,14154,8926,11830,8784,\r
+2987,9634,6670,13501,13957,4260,5761,15347,\r
+7991,13414,7159,7233,14206,11665,6715,11079,\r
+3545,5185,15639,14307,9338,8971,15994,5645,\r
+3098,14081,788,8170,10188,8016,5988,15919,\r
+12788,14960,10214,12606,11152,2470,13420,2927,\r
+5240,7370,9648,10099,2039,4846,10610,11823,\r
+13270,14761,5962,7512,10079,4867,8260,2135,\r
+1052,10823,5729,10395,14361,13382,12200,8162,\r
+5117,7531,13361,14520,10602,8685,3654,9777,\r
+16263,6135,6389,11745,10383,8550,12618,10340,\r
+4128,15459,7062,5135,9047,9346,5897,15479,\r
+7268,5576,0,14937,12736,5545,10079,6507,\r
+3238,3204,9865,5843,12487,198,8251,13195,\r
+158,8913,6598,4373,15991,13857,3615,11106,\r
+3244,10654,6394,6183,11633,3098,12257,15427,\r
+1768,7209,11987,963,13857,7247,16046,7239,\r
+13200,11773,2914,12927,11669,13011,1905,9089,\r
+16176,3743,158,5222,12717,5825,16087,9519,\r
+9227,15563,1712,8511,11005,4867,13200,13106,\r
+10788,3606,8680,3447,5833,3709,4526,10847,\r
+2871,6000,2204,15769,2969,7617,15976,7618,\r
+4067,10757,15316,6476,10509,8772,9095,0,\r
+8996,410,14742,7239,10532,9406,7419,15903,\r
+5437,5560,12608,9141,3986,14358,7409,3992,\r
+3221,6170,11821,508,6434,1442,4260,3813,\r
+8308,6456,3534,431,4538,3406,12435,5643,\r
+7144,8870,9186,3775,1817,9905,7951,4336,\r
+2273,12264,6513,2993,16270,5541,5077,6263,\r
+1259,2559,1675,16218,1790,12804,15098,4445,\r
+10336,15216,12144,8618,4573,13679,15000,10189,\r
+2209,4583,5353,13784,2623,7720,5833,11064,\r
+10088,10077,10610,6786,10939,10867,1768,8119,\r
+7394,12056,3789,1074,15413,10527,7247,12487,\r
+8568,10136,2228,13412,4840,1652,6740,11322,\r
+5037,2910,5174,10340,2135,8011,11895,11895,\r
+109,11957,14336,13234,8225,14343,9063,9819,\r
+13517,11635,13549,14936,988,3809,5833,7857,\r
+13462,297,7668,14482,4316,10848,2569,13931,\r
+5593,12056,11103,14170,448,902,1768,11552,\r
+6043,0,0,8646,10391,0,15316,3737,\r
+10594,11026,13280,14667,5713,4057,2787,4191,\r
+3838,7247,8772,14185,15641,8772,0,14081,\r
+0,9429,17,613,7428,15131,15651,14350,\r
+4365,15856,9521,3228,7950,3395,0,6594,\r
+11078,14975,6889,10768,4288,6707,7175,2235,\r
+10896,911,7707,7592,12916,15570,15644,6997,\r
+12523,14757,11895,7109,16279,12969,11690,0,\r
+8854,16304,8568,11334,15641,15478,2275,6193,\r
+7323,5230,9835,12821,1652,12477,5044,359,\r
+12487,13881,10731,8246,14642,14885,6555,15919,\r
+13857,1982,7646,12528,12009,7310,12310,3193,\r
+359,1483,5322,10476,46,3751,3766,6729,\r
+4512,13853,5558,12736,1733,2718,9956,7857,\r
+6519,2187,12964,12949,750,8877,15136,3742,\r
+4495,13851,3811,906,11592,9943,920,10806,\r
+10442,12561,5035,988,15861,8024,10272,16372,\r
+13353,15946,7330,4834,9414,8267,1668,12498,\r
+4530,9162,8648,3883,9451,3900,2028,12427,\r
+11203,3071,5645,10228,11875,8198,4563,215,\r
+3614,5717,11332,1617,11382,13987,12626,11857,\r
+12156,6513,13496,6997,16158,9093,6725,13737,\r
+5890,10008,14447,5475,12215,141,16192,10200,\r
+4450,6688,11090,16109,12256,9027,15355,3422,\r
+10079,14571,13101,9967,12296,3460,8348,15413,\r
+5222,11762,3823,13412,6729,6599,10528,9922,\r
+11152,9171,5362,5373,750,8969,1652,6220,\r
+5373,2569,3742,15119,10340,999,10088,10731,\r
+1028,3228,7369,15256,11822,12904,8121,11641,\r
+11158,5016,10725,8412,1183,9674,11806,12112,\r
+2623,15516,4226,10021,13316,12075,792,4972,\r
+8506,8921,6133,14718,567,4349,13420,5953,\r
+2265,11902,10019,16265,16312,0,9922,3009,\r
+8170,3473,10757,3567,2825,6915,5174,4299,\r
+0,8274,6292,295,6522,1475,359,4538,\r
+5358,5174,3008,6317,12688,4165,752,12052,\r
+10008,3912,7431,13364,9894,13524,284,16013,\r
+9820,11295,1144,2845,3538,10678,13806,1469,\r
+14210,7870,3766,10528,13642,10823,4200,8031,\r
+4671,14093,5541,1214,4115,3286,8217,8018 };\r
+\r
+\r
+unsigned int phash( unsigned int move, int turn )\r
+{\r
+ unsigned int a, b;\r
+ \r
+ move |= ( (unsigned int)turn << 31 );\r
+ move += 0x69fe378e;\r
+ move ^= ( move >> 16 );\r
+ move += ( move << 8 );\r
+ move ^= ( move >> 4 );\r
+ b = ( move >> 7 ) & 0x7ff;\r
+ a = move >> 18;\r
+ \r
+ return a ^ tab[b];\r
+}\r
--- /dev/null
+#include <stdlib.h>
+#include <limits.h>
+#include "shogi.h"
+
+
+int
+ponder( tree_t * restrict ptree )
+{
+ const char *str;
+ unsigned int move;
+ int iret;
+
+ if ( ( game_status & ( mask_game_end | flag_noponder | flag_nopeek ) )
+ || abs( last_root_value ) > score_max_eval
+ || ! record_game.moves
+ || sec_limit_up == UINT_MAX ) { return 1; }
+
+ ponder_nmove = gen_legal_moves( ptree, ponder_move_list );
+
+ if ( get_elapsed( &time_start ) < 0 ) { return -1; }
+
+ Out( "\nSearch a move to ponder\n\n" );
+ OutCsaShogi( "info ponder start\n" );
+
+ game_status |= flag_puzzling;
+ iret = iterate( ptree, 0 );
+ game_status &= ~flag_puzzling;
+ if ( iret < 0 ) { return iret; }
+
+ if ( game_status & ( flag_quit | flag_quit_ponder | flag_suspend ) )
+ {
+ OutCsaShogi( "info ponder end\n" );
+ return 1;
+ }
+
+ if ( abs(last_root_value) > score_max_eval )
+ {
+ OutCsaShogi( "info ponder end\n" );
+ return 1;
+ }
+
+ ponder_move = move = last_pv.a[1];
+ str = str_CSA_move( move );
+ Out( "\nPonder on %c%s (%+.2f)\n\n",
+ ach_turn[root_turn], str, (double)last_root_value / 100.0 );
+
+ iret = make_move_root( ptree, move, ( flag_rep | flag_rejections ) );
+ if ( iret < 0 )
+ {
+ OutCsaShogi( "info ponder end\n" );
+ return iret;
+ }
+
+ if ( game_status & mask_game_end )
+ {
+ OutCsaShogi( "info ponder end\n" );
+ unmake_move_root( ptree, move );
+ return 1;
+ }
+
+ if ( get_elapsed( &time_start ) < 0 ) { return -1; }
+
+ game_status |= flag_pondering;
+
+ iret = iterate( ptree, 0 );
+ if ( game_status & flag_thinking )
+ {
+ game_status &= ~flag_thinking;
+ if ( iret < 0 ) { return iret; }
+
+ iret = com_turn_start( ptree, flag_from_ponder );
+ if ( iret < 0 ) { return iret; }
+
+ return 2;
+ }
+ OutCsaShogi( "info ponder end\n" );
+ game_status &= ~flag_pondering;
+ unmake_move_root( ptree, move );
+
+ return iret;
+}
+
+
+#if defined(MNJ_LAN)
+int
+analyze( tree_t * restrict ptree )
+{
+ int iret;
+
+ if ( game_status & mask_game_end ) { return 1; }
+
+ iret = get_elapsed( &time_start );
+ if ( iret < 0 ) { return iret; }
+
+ game_status |= flag_pondering;
+ iret = iterate( ptree, 0 );
+ game_status &= ~flag_pondering;
+
+ if ( abs(last_root_value) > score_max_eval )
+ {
+ MnjOut( "pid=%d confident\n", mnj_posi_id );
+ }
+
+ return iret;
+}
+#endif
--- /dev/null
+#include "shogi.h"
+
+int
+solve_problems( tree_t * restrict ptree, unsigned int nposition )
+{
+ const char *str_move;
+ uint64_t total_node;
+ unsigned int game_status_save, move, uposition, te1, te0;
+ int iret, success, failure, ianswer, istatus, iresult;
+
+ success = failure = 0;
+ total_node = 0;
+ if ( get_elapsed( &te0 ) < 0 ) { return -1; };
+
+ for ( uposition = 0; uposition < nposition; uposition++ )
+ {
+ istatus = in_CSA( ptree, &record_problems, NULL,
+ ( flag_nomake_move | flag_detect_hang
+ | flag_rejections ) );
+ if ( istatus < 0 ) { return istatus; }
+
+ if ( istatus > record_next )
+ {
+ snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+ record_problems.lines, str_bad_record );
+ str_error = str_message;
+ return -2;
+ }
+
+ /* examine all of answers */
+ Out( "Answers:" );
+ for ( ianswer = 0; ianswer < MAX_ANSWER; ianswer++ )
+ {
+ str_move = &( record_problems.info.str_move[ianswer][0] );
+ if ( str_move[0] == '\0' ) { break; }
+ if ( ( root_turn && str_move[0] != '-' )
+ || ( ! root_turn && str_move[0] != '+' ) )
+ {
+ snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+ record_problems.lines,
+ "Answers has invalid sign of turn." );
+ str_error = str_message;
+ return -2;
+ }
+
+ iret = interpret_CSA_move( ptree, &move, str_move+1 );
+ if ( iret < 0 ) { return iret; }
+
+ iret = make_move_root( ptree, move, ( flag_detect_hang | flag_rep
+ | flag_nomake_move ) );
+ if ( iret < 0 ) { return iret; }
+
+ Out( "%s ", str_move );
+ }
+ Out( "\n" );
+ if ( ! ianswer )
+ {
+ snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
+ record_problems.lines,
+ "No answers in the record" );
+ str_error = str_message;
+ return -2;
+ }
+
+ iret = out_board( ptree, stdout, 0, 0 );
+ if ( iret < 0 ) { return iret; }
+
+ if ( get_elapsed( &time_start ) < 0 ) { return -1; };
+ time_turn_start = time_start;
+
+ game_status_save = game_status;
+ game_status |= flag_problem | flag_nopeek | flag_thinking;
+ iresult = iterate( ptree, 0 );
+ game_status = game_status_save;
+ if ( iresult < 0 ) { return iresult; }
+
+ if ( iresult ) { success++; }
+ else { failure++; }
+
+ total_node += ptree->node_searched;
+
+ str_move = str_CSA_move( last_pv.a[1] );
+ Out( "problem #%d answer=%s -- %s (correct=%d, incorrect=%d)\n\n",
+ success+failure, str_move, iresult ? "correct" : "incorrect",
+ success, failure );
+
+ if ( istatus == record_eof ) { break; }
+ if ( istatus == record_misc )
+ {
+ iret = record_wind( &record_problems );
+ if ( iret < 0 ) { return iret; }
+ if ( iret == record_eof ) { break; }
+ }
+ }
+
+ if ( get_elapsed( &te1 ) < 0 ) { return -1; }
+
+ Out( "Total Nodes: %" PRIu64 "\n", total_node );
+ Out( "Total Elapsed: %.2f\n", (double)( te1 - te0 ) / 1000.0 );
+
+ return 1;
+}
--- /dev/null
+#include <ctype.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "shogi.h"
+
+/* unacceptable when the program is thinking, or quit pondering */
+#define AbortDifficultCommand \
+ if ( game_status & flag_thinking ) \
+ { \
+ str_error = str_busy_think; \
+ return -2; \
+ } \
+ else if ( game_status & ( flag_pondering | flag_puzzling ) ) \
+ { \
+ game_status |= flag_quit_ponder; \
+ return 2; \
+ }
+
+#if defined(MINIMUM)
+# define CmdBook(x,y) cmd_book(y);
+static int cmd_book( char **lasts );
+#else
+# define CmdBook(x,y) cmd_book(x,y);
+static int cmd_learn( tree_t * restrict ptree, char **lasts );
+static int cmd_book( tree_t * restrict ptree, char **lasts );
+#endif
+
+#if ! defined(NO_STDOUT)
+static int cmd_stress( char **lasts );
+#endif
+
+#if defined(DEKUNOBOU)
+static int cmd_dek( char **lasts );
+#endif
+
+#if defined(CSA_LAN)
+static int proce_csalan( tree_t * restrict ptree );
+static int cmd_connect( tree_t * restrict ptree, char **lasts );
+#endif
+
+#if defined(MNJ_LAN)
+static int proce_mnj( tree_t * restrict ptree );
+static int cmd_mnj( tree_t * restrict ptree, char **lasts );
+static int cmd_mnjmove( tree_t * restrict ptree, char **lasts, int is_alter );
+#endif
+
+#if defined(TLP)
+static int cmd_thread( char **lasts );
+#endif
+
+#if defined(MPV)
+static int cmd_mpv( char **lasts );
+#endif
+
+static int proce_cui( tree_t * restrict ptree );
+static int cmd_usrmove( tree_t * restrict ptree, const char *str_move,
+ char **last );
+static int cmd_move_now( void );
+static int cmd_ponder( char **lasts );
+static int cmd_limit( char **lasts );
+static int cmd_quit( void );
+static int cmd_beep( char **lasts );
+static int cmd_peek( char **lasts );
+static int cmd_hash( char **lasts );
+static int cmd_ping( void );
+static int cmd_suspend( void );
+static int cmd_problem( tree_t * restrict ptree, char **lasts );
+static int cmd_display( tree_t * restrict ptree, char **lasts );
+static int cmd_move( tree_t * restrict ptree, char **lasts );
+static int cmd_new( tree_t * restrict ptree, char **lasts );
+static int cmd_read( tree_t * restrict ptree, char **lasts );
+static int cmd_resign( tree_t * restrict ptree, char **lasts );
+static int cmd_time( char **lasts );
+static int is_move( const char *str );
+
+
+int
+procedure( tree_t * restrict ptree )
+{
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL ) { return proce_csalan( ptree ); }
+#endif
+#if defined(MNJ_LAN)
+ if ( sckt_mnj != SCKT_NULL ) { return proce_mnj( ptree ); }
+#endif
+
+ return proce_cui( ptree );
+}
+
+
+static int
+proce_cui( tree_t * restrict ptree )
+{
+ const char *token;
+ char *last;
+
+ token = strtok_r( str_cmdline, str_delimiters, &last );
+
+ if ( token == NULL || *token == '#' ) { return 1; }
+ if ( is_move( token ) ) { return cmd_usrmove( ptree, token, &last ); }
+ if ( ! strcmp( token, "s" ) ) { return cmd_move_now(); }
+ if ( ! strcmp( token, "beep" ) ) { return cmd_beep( &last); }
+ if ( ! strcmp( token, "book" ) ) { return CmdBook( ptree, &last ); }
+ if ( ! strcmp( token, "display" ) ) { return cmd_display( ptree, &last ); }
+ if ( ! strcmp( token, "hash" ) ) { return cmd_hash( &last ); }
+ if ( ! strcmp( token, "limit" ) ) { return cmd_limit( &last ); }
+ if ( ! strcmp( token, "move" ) ) { return cmd_move( ptree, &last ); }
+ if ( ! strcmp( token, "new" ) ) { return cmd_new( ptree, &last ); }
+ if ( ! strcmp( token, "peek" ) ) { return cmd_peek( &last ); }
+ if ( ! strcmp( token, "ping" ) ) { return cmd_ping(); }
+ if ( ! strcmp( token, "ponder" ) ) { return cmd_ponder( &last ); }
+ if ( ! strcmp( token, "problem" ) ) { return cmd_problem( ptree, &last ); }
+ if ( ! strcmp( token, "quit" ) ) { return cmd_quit(); }
+ if ( ! strcmp( token, "read" ) ) { return cmd_read( ptree, &last ); }
+ if ( ! strcmp( token, "resign" ) ) { return cmd_resign( ptree, &last ); }
+ if ( ! strcmp( token, "suspend" ) ) { return cmd_suspend(); }
+ if ( ! strcmp( token, "time" ) ) { return cmd_time( &last ); }
+#if defined(CSA_LAN)
+ if ( ! strcmp( token, "connect" ) ) { return cmd_connect( ptree, &last ); }
+#endif
+#if defined(MNJ_LAN)
+ if ( ! strcmp( token, "mnj" ) ) { return cmd_mnj( ptree, &last ); }
+#endif
+#if defined(DEKUNOBOU)
+ if ( ! strcmp( token, "dekunobou" ) ) { return cmd_dek( &last ); }
+#endif
+#if defined(MPV)
+ if ( ! strcmp( token, "mpv" ) ) { return cmd_mpv( &last ); }
+#endif
+#if defined(TLP)
+ if ( ! strcmp( token, "tlp" ) ) { return cmd_thread( &last ); }
+#endif
+#if ! defined(NO_STDOUT)
+ if ( ! strcmp( token, "stress" ) ) { return cmd_stress( &last ); }
+#endif
+#if ! defined(MINIMUM)
+ if ( ! strcmp( token, "learn" ) ) { return cmd_learn( ptree, &last ); }
+#endif
+
+ str_error = str_bad_cmdline;
+ return -2;
+}
+
+
+#if defined(CSA_LAN)
+static int
+proce_csalan( tree_t * restrict ptree )
+{
+ const char *token;
+ char *last;
+
+ token = strtok_r( str_cmdline, str_delimiters, &last );
+
+ if ( token == NULL ) { return 1; }
+ if ( *token == ach_turn[client_turn] && is_move( token+1 ) )
+ {
+ char *ptr;
+ long l;
+
+ token = strtok_r( NULL, str_delimiters, &last );
+ if ( token == NULL || *token != 'T' )
+ {
+ str_error = str_bad_cmdline;
+ return -1;
+ }
+
+ l = strtol( token+1, &ptr, 0 );
+ if ( token+1 == ptr || l == LONG_MAX || l < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -1;
+ }
+
+ adjust_time( (unsigned int)l, client_turn );
+ Out( " elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
+ return 1;
+ }
+ if ( *token == ach_turn[Flip(client_turn)] && is_move( token+1 ) )
+ {
+ return cmd_usrmove( ptree, token+1, &last );
+ }
+ if ( ! strcmp( token, str_resign ) ) { return cmd_resign( ptree, &last ); }
+ if ( ! strcmp( token, "#WIN" )
+ || ! strcmp( token, "#LOSE" )
+ || ! strcmp( token, "#DRAW" )
+ || ! strcmp( token, "#CHUDAN" ) )
+ {
+ if ( game_status & ( flag_thinking | flag_pondering | flag_puzzling ) )
+ {
+ game_status |= flag_suspend;
+ return 2;
+ }
+
+ ShutdownClient;
+
+ if ( client_ngame == client_max_game ) { return cmd_quit(); }
+
+ return client_next_game( ptree, client_str_addr, (int)client_port );
+ }
+
+ return 1;
+}
+#endif
+
+
+#if defined(MNJ_LAN)
+static int
+proce_mnj( tree_t * restrict ptree )
+{
+ const char *token;
+ char *last;
+ int iret;
+
+ token = strtok_r( str_cmdline, str_delimiters, &last );
+ if ( token == NULL ) { return 1; }
+
+ if ( ! strcmp( token, "new" ) )
+ {
+ iret = cmd_suspend();
+ if ( iret != 1 ) { return iret; }
+
+ mnj_posi_id = 0;
+ iret = cmd_new( ptree, &last );
+ if ( iret < 0 ) { return iret; }
+
+ return analyze( ptree );
+ }
+ if ( ! strcmp( token, "idle" ) ) { return cmd_suspend(); }
+ if ( ! strcmp( token, "alter" ) ) { return cmd_mnjmove( ptree, &last, 1 ); }
+ if ( ! strcmp( token, "move" ) ) { return cmd_mnjmove( ptree, &last, 0 ); }
+
+ str_error = str_bad_cmdline;
+ return -2;
+}
+
+
+static int
+cmd_mnjmove( tree_t * restrict ptree, char **lasts, int is_alter )
+{
+ const char *str1 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long lid;
+ unsigned int move;
+ int iret;
+
+ if ( sckt_mnj == SCKT_NULL || str1 == NULL || str2 == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -1;
+ }
+
+ lid = strtol( str2, &ptr, 0 );
+ if ( ptr == str2 || lid == LONG_MAX || lid < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -1;
+ }
+
+ AbortDifficultCommand;
+
+ if ( is_alter ) { unmake_move_root( ptree, mnj_move_last ); };
+
+ iret = interpret_CSA_move( ptree, &move, str1 );
+ if ( iret < 0 ) { return iret; }
+
+ iret = get_elapsed( &time_turn_start );
+ if ( iret < 0 ) { return iret; }
+
+ mnj_posi_id = (int)lid;
+ mnj_move_last = move;
+
+ iret = make_move_root( ptree, move, ( flag_history | flag_time | flag_rep
+ | flag_detect_hang
+ | flag_rejections ) );
+ if ( iret < 0 ) { return iret; }
+
+# if ! defined(NO_STDOUT)
+ iret = out_board( ptree, stdout, 0, 0 );
+ if ( iret < 0 ) { return iret; }
+# endif
+
+ return analyze( ptree );
+}
+#endif
+
+
+static int
+is_move( const char *str )
+{
+ if ( isdigit( (int)str[0] ) && isdigit( (int)str[1] )
+ && isdigit( (int)str[2] ) && isdigit( (int)str[3] )
+ && isupper( (int)str[4] ) && isupper( (int)str[5] )
+ && str[6] == '\0' ) { return 1; }
+
+ return 0;
+}
+
+
+static int
+cmd_move_now( void )
+{
+ if ( game_status & flag_thinking ) { game_status |= flag_move_now; }
+
+ return 1;
+}
+
+
+static int
+cmd_usrmove( tree_t * restrict ptree, const char *str_move, char **lasts )
+{
+ const char *str;
+ char *ptr;
+ long lelapsed;
+ unsigned int move;
+ int iret;
+
+ if ( game_status & mask_game_end )
+ {
+ str_error = str_game_ended;
+ return -2;
+ }
+
+ if ( game_status & flag_thinking )
+ {
+ str_error = str_busy_think;
+ return -2;
+ }
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL ) { lelapsed = 0; }
+ else {
+ if ( *str != 'T' )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ str += 1;
+ lelapsed = strtol( str, &ptr, 0 );
+ if ( ptr == str || lelapsed == LONG_MAX || lelapsed < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ }
+
+ if ( game_status & ( flag_pondering | flag_puzzling ) )
+ {
+ int i;
+
+ for ( i = 0; i < ponder_nmove; i++ )
+ {
+ if ( ! strcmp( str_move, str_CSA_move(ponder_move_list[i]) ) )
+ {
+ break;
+ }
+ }
+ if ( i == ponder_nmove )
+ {
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL ) { AbortDifficultCommand; }
+#endif
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame ) { AbortDifficultCommand; }
+#endif
+
+#if defined(CSASHOGI)
+ AbortDifficultCommand;
+#else
+ str_error = str_illegal_move;
+ return -2;
+#endif
+ }
+
+ if ( ( game_status & flag_puzzling )
+ || strcmp( str_move, str_CSA_move(ponder_move) ) )
+ {
+ ponder_move = MOVE_PONDER_FAILED;
+ game_status |= flag_quit_ponder;
+ return 2;
+ }
+ else {
+ iret = renovate_time( Flip(root_turn) );
+ if ( iret < 0 ) { return iret; }
+ if ( lelapsed )
+ {
+ adjust_time( (unsigned int)lelapsed, Flip(root_turn) );
+ }
+
+ history_book_learn[ record_game.moves ].move_played = ponder_move;
+ history_book_learn[ record_game.moves ].hand_played
+ = ptree->rep_hand_list[ root_nrep-1 ];
+ history_book_learn[ record_game.moves ].key_played
+ = (unsigned int)ptree->rep_board_list[ root_nrep-1 ];
+
+ out_CSA( ptree, &record_game, ponder_move );
+
+ game_status &= ~flag_pondering;
+ game_status |= flag_thinking;
+ n_nobook_move += 1;
+ set_search_limit_time( root_turn );
+
+ OutCsaShogi( "info ponder end\n" );
+
+ str = str_time_symple( time_turn_start - time_start );
+ Out( " %6s MOVE PREDICTION HIT\n"
+ " elapsed: b%u, w%u\n", str, sec_b_total, sec_w_total );
+ return 1;
+ }
+ }
+
+ iret = interpret_CSA_move( ptree, &move, str_move );
+ if ( iret < 0 ) { return iret; }
+ move_evasion_pchk = 0;
+ iret = make_move_root( ptree, move, ( flag_rep | flag_history | flag_time
+ | flag_rejections
+ | flag_detect_hang ) );
+ if ( iret < 0 )
+ {
+
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL )
+ {
+ if ( move_evasion_pchk )
+ {
+ str = str_CSA_move( move_evasion_pchk );
+ iret = sckt_out( sckt_csa, "%c%s\n",
+ ach_turn[Flip(root_turn)], str );
+ if ( iret < 0 ) { return iret; }
+ }
+ return cmd_suspend();
+ }
+#endif
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame )
+ {
+ if ( move_evasion_pchk )
+ {
+ dek_win += 1;
+ OutDek( "%%TORYO\n" );
+ }
+ return cmd_suspend();
+ }
+#endif
+
+ if ( move_evasion_pchk )
+ {
+ str = str_CSA_move( move_evasion_pchk );
+#if defined(CSASHOGI)
+ OutCsaShogi( "move%s\n", str );
+ return cmd_suspend();
+#else
+ snprintf( str_message, SIZE_MESSAGE, "perpetual check (%c%s)",
+ ach_turn[Flip(root_turn)], str );
+ str_error = str_message;
+ return -2;
+#endif
+ }
+
+ return iret;
+ }
+
+ if ( lelapsed ) { adjust_time( (unsigned int)lelapsed, Flip(root_turn) ); }
+ Out( " elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
+
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL && ( game_status & flag_mated ) )
+ {
+ iret = sckt_out( sckt_csa, "%%TORYO\n" );
+ if ( iret < 0 ) { return iret; }
+ }
+#endif
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame && ( game_status & flag_drawn ) ) { OutDek( "%%TORYO\n" ); }
+#endif
+
+ if ( ! ( game_status & mask_game_end ) )
+ {
+ iret = com_turn_start( ptree, 0 );
+ if ( iret < 0 ) { return iret; }
+ }
+
+ return 1;
+}
+
+
+static int
+cmd_beep( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ if ( ! strcmp( str, str_on ) ) { game_status &= ~flag_nobeep; }
+ else if ( ! strcmp( str, str_off ) ) { game_status |= flag_nobeep; }
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ return 1;
+}
+
+
+static int
+cmd_peek( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ if ( ! strcmp( str, str_on ) ) { game_status &= ~flag_nopeek; }
+ else if ( ! strcmp( str, str_off ) ) { game_status |= flag_nopeek; }
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ return 1;
+}
+
+
+static int
+cmd_ponder( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ if ( ! strcmp( str, str_on ) ) { game_status &= ~flag_noponder; }
+ else if ( ! strcmp( str, str_off ) )
+ {
+ if ( game_status & ( flag_pondering | flag_puzzling ) )
+ {
+ game_status |= flag_quit_ponder;
+ }
+ game_status |= flag_noponder;
+ }
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ return 1;
+}
+
+
+#if ! defined(NO_STDOUT)
+static int
+cmd_stress( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ if ( ! strcmp( str, str_on ) ) { game_status &= ~flag_nostress; }
+ else if ( ! strcmp( str, str_off ) ) { game_status |= flag_nostress; }
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ return 1;
+}
+#endif
+
+
+static int
+#if defined(MINIMUM)
+cmd_book( char **lasts )
+#else
+cmd_book( tree_t * restrict ptree, char **lasts )
+#endif
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ int iret = 1;
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ if ( ! strcmp( str, str_on ) ) { iret = book_on(); }
+ else if ( ! strcmp( str, str_off ) ) { iret = book_off(); }
+ else if ( ! strcmp( str, "narrow" ) ) { game_status |= flag_narrow_book; }
+ else if ( ! strcmp( str, "wide" ) ) { game_status &= ~flag_narrow_book; }
+#if ! defined(MINIMUM)
+ else if ( ! strcmp( str, "create" ) )
+ {
+ AbortDifficultCommand;
+
+ iret = book_create( ptree );
+ if ( iret < 0 ) { return iret; }
+
+ iret = ini_game( ptree, &min_posi_no_handicap, flag_history,
+ NULL, NULL );
+ if ( iret < 0 ) { return iret; }
+
+ iret = get_elapsed( &time_turn_start );
+ }
+#endif
+ else {
+ str_error = str_bad_cmdline;
+ iret = -2;
+ }
+
+ return iret;
+}
+
+
+static int
+cmd_display( tree_t * restrict ptree, char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long l;
+ int iret;
+
+ if ( str != NULL )
+ {
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ if ( l == 1 ) { game_status &= ~flag_reverse; }
+ else if ( l == 2 ) { game_status |= flag_reverse; }
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ }
+
+ Out( "\n" );
+ iret = out_board( ptree, stdout, 0, 0 );
+ if ( iret < 0 ) { return iret; }
+#if ! defined(NO_LOGGING)
+ iret = out_board( ptree, pf_log, 0, 0 );
+ if ( iret < 0 ) { return iret; }
+#endif
+ Out( "\n" );
+
+ return 1;
+}
+
+
+static int
+cmd_ping( void )
+{
+ OutCsaShogi( "pong\n" );
+ Out( "pong\n" );
+ return 1;
+}
+
+
+static int
+cmd_hash( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long l;
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ if ( ! strcmp( str, "learn" ) )
+ {
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str != NULL && ! strcmp( str, str_on ) )
+ {
+ return hash_learn_on();
+ }
+ else if ( str != NULL && ! strcmp( str, str_off ) )
+ {
+ return hash_learn_off();
+ }
+#if ! defined(MINIMUM)
+ else if ( str != NULL && ! strcmp( str, "create" ) )
+ {
+ return hash_learn_create();
+ }
+#endif
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ }
+
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < 1 || l > 31 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ AbortDifficultCommand;
+
+ log2_ntrans_table = (int)l;
+ memory_free( (void *)ptrans_table_orig );
+ return ini_trans_table();
+}
+
+
+static int
+cmd_limit( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long l1, l2, l3;
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ AbortDifficultCommand;
+
+ if ( ! strcmp( str, "depth" ) )
+ {
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l1 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l1 == LONG_MAX || l1 < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ sec_limit_up = UINT_MAX;
+ node_limit = UINT64_MAX;
+ depth_limit = (int)l1;
+ }
+ else if ( ! strcmp( str, "nodes" ) )
+ {
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l1 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l1 == LONG_MAX || l1 < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ sec_limit_up = UINT_MAX;
+ depth_limit = PLY_MAX;
+ node_limit = (uint64_t)l1;
+ }
+ else if ( ! strcmp( str, "time" ) )
+ {
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ if ( ! strcmp( str, "extendable" ) )
+ {
+ game_status |= flag_time_extendable;
+ }
+ else if ( ! strcmp( str, "strict" ) )
+ {
+ game_status &= ~flag_time_extendable;
+ }
+ else {
+ l1 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l1 == LONG_MAX || l1 < 0 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l2 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l2 == LONG_MAX || l2 < 0 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str ) { l3 = -1; }
+ else {
+ l3 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l3 >= PLY_MAX || l3 < -1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ }
+
+ if ( ! ( l1 | l2 ) ) { l2 = 1; }
+
+ depth_limit = PLY_MAX;
+ node_limit = UINT64_MAX;
+ sec_limit = (unsigned int)l1 * 60U;
+ sec_limit_up = (unsigned int)l2;
+ if ( l3 == -1 ) { sec_limit_depth = UINT_MAX; }
+ else { sec_limit_depth = (unsigned int)l3; }
+ }
+ }
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ return 1;
+}
+
+
+static int
+cmd_read( tree_t * restrict ptree, char **lasts )
+{
+ const char *str1 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str3 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str_tmp;
+ FILE *pf_src, *pf_dest;
+ char str_file[SIZE_FILENAME];
+ char *ptr;
+ unsigned int moves;
+ long l;
+ int iret, flag, c;
+
+ flag = flag_history | flag_rep | flag_detect_hang | flag_rejections;
+ moves = UINT_MAX;
+ str_tmp = NULL;
+
+ if ( str1 == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ if ( str2 != NULL )
+ {
+ if ( ! strcmp( str2, "t" ) ) { flag |= flag_time; }
+ else if ( strcmp( str2, "nil" ) )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ }
+
+ if ( str3 != NULL )
+ {
+ l = strtol( str3, &ptr, 0 );
+ if ( ptr == str3 || l == LONG_MAX || l < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ moves = (unsigned int)l - 1U;
+ }
+
+ AbortDifficultCommand;
+
+ if ( ! strcmp( str1, "." ) )
+ {
+ str_tmp = "game.cs_";
+
+#if defined(NO_LOGGING)
+ strncpy( str_file, "game.csa", SIZE_FILENAME-1 );
+#else
+ snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
+ str_dir_logs, irecord_game );
+#endif
+ pf_dest = file_open( str_tmp, "w" );
+ if ( pf_dest == NULL ) { return -2; }
+
+ pf_src = file_open( str_file, "r" );
+ if ( pf_src == NULL )
+ {
+ file_close( pf_dest );
+ return -2;
+ }
+
+ while ( ( c = getc(pf_src) ) != EOF ) { putc( c, pf_dest ); }
+
+ iret = file_close( pf_src );
+ if ( iret < 0 )
+ {
+ file_close( pf_dest );
+ return iret;
+ }
+
+ iret = file_close( pf_dest );
+ if ( iret < 0 ) { return iret; }
+
+ flag |= flag_time;
+ str1 = str_tmp;
+ }
+
+ iret = read_record( ptree, str1, moves, flag );
+ if ( iret < 0 ) { return iret; }
+
+ iret = get_elapsed( &time_turn_start );
+ if ( iret < 0 ) { return iret; }
+
+ if ( str_tmp && remove( str_tmp ) )
+ {
+ out_warning( "remove() failed." );
+ return -2;
+ }
+
+ return 1;
+}
+
+
+static int
+cmd_resign( tree_t * restrict ptree, char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long l;
+
+ if ( str == NULL || *str == 'T' )
+ {
+ AbortDifficultCommand;
+
+ if ( game_status & mask_game_end ) { return 1; }
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame && record_game.moves < 2 )
+ {
+ str_error = "ignore resignation";
+ return -2;
+ }
+#endif
+
+ game_status |= flag_resigned;
+ renovate_time( root_turn );
+ out_CSA( ptree, &record_game, MOVE_RESIGN );
+ }
+ else {
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < MT_CAP_PAWN )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ resign_threshold = (int)l;
+ }
+
+ return 1;
+}
+
+
+static int
+cmd_move( tree_t * restrict ptree, char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ unsigned int move;
+ int iret;
+
+ if ( game_status & mask_game_end )
+ {
+ str_error = str_game_ended;
+ return -2;
+ }
+
+ AbortDifficultCommand;
+
+ if ( str == NULL )
+ {
+ iret = get_elapsed( &time_turn_start );
+ if ( iret < 0 ) { return iret; }
+
+ iret = com_turn_start( ptree, 0 );
+ if ( iret < 0 ) { return iret; }
+ }
+ else if ( ! strcmp( str, "restraint" ) )
+ {
+ iret = get_elapsed( &time_turn_start );
+ if ( iret < 0 ) { return iret; }
+
+ iret = com_turn_start( ptree, flag_refer_rest );
+ if ( iret < 0 ) { return iret; }
+ }
+ else {
+
+ iret = interpret_CSA_move( ptree, &move, str );
+ if ( iret < 0 ) { return iret; }
+
+ iret = get_elapsed( &time_turn_start );
+ if ( iret < 0 ) { return iret; }
+
+#if defined(MNJ_LAN)
+ if ( sckt_mnj != SCKT_NULL )
+ {
+ const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long l;
+ if ( str2 ) { l = strtol( str2, &ptr, 0 ); }
+ if ( ! str2 || ptr == str || l == LONG_MAX || l < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ mnj_posi_id = (int)l;
+ mnj_move_last = move;
+ }
+#endif
+
+ iret = make_move_root( ptree, move, ( flag_history | flag_time | flag_rep
+ | flag_detect_hang
+ | flag_rejections ) );
+ if ( iret < 0 ) { return iret; }
+ }
+
+ return 1;
+}
+
+
+static int
+cmd_new( tree_t * restrict ptree, char **lasts )
+{
+ const char *str1 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+ const min_posi_t *pmp;
+ min_posi_t min_posi;
+ int iret;
+
+ AbortDifficultCommand;
+
+ if ( str1 != NULL )
+ {
+ memset( &min_posi.asquare, empty, nsquare );
+ min_posi.hand_black = min_posi.hand_white = 0;
+ iret = read_board_rep1( str1, &min_posi );
+ if ( iret < 0 ) { return iret; }
+
+ if ( str2 != NULL )
+ {
+ if ( ! strcmp( str2, "-" ) ) { min_posi.turn_to_move = white; }
+ else if ( ! strcmp( str2, "+" ) ) { min_posi.turn_to_move = black; }
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ }
+ else { min_posi.turn_to_move = black; }
+
+ pmp = &min_posi;
+ }
+ else { pmp = &min_posi_no_handicap; }
+
+ iret = ini_game( ptree, pmp, flag_history, NULL, NULL );
+ if ( iret < 0 ) { return iret; }
+
+ return get_elapsed( &time_turn_start );
+}
+
+
+static int
+cmd_problem( tree_t * restrict ptree, char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long l;
+ unsigned int nposition;
+ int iret;
+
+ if ( str != NULL )
+ {
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ nposition = (unsigned int)l;
+ }
+ else { nposition = UINT_MAX; }
+
+ AbortDifficultCommand;
+
+ iret = record_open( &record_problems, "problem.csa", mode_read, NULL, NULL );
+ if ( iret < 0 ) { return iret; }
+
+ iret = solve_problems( ptree, nposition );
+ if ( iret < 0 )
+ {
+ record_close( &record_problems );
+ return iret;
+ }
+
+ iret = record_close( &record_problems );
+ if ( iret < 0 ) { return iret; }
+
+ iret = ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL );
+ if ( iret < 0 ) { return iret; }
+
+ return get_elapsed( &time_turn_start );
+}
+
+
+static int
+cmd_quit( void )
+{
+ game_status |= flag_quit;
+ return 1;
+}
+
+
+static int
+cmd_suspend( void )
+{
+ if ( game_status & ( flag_pondering | flag_puzzling ) )
+ {
+ game_status |= flag_quit_ponder;
+ return 2;
+ }
+
+ game_status |= flag_suspend;
+ return 1;
+}
+
+
+static int
+cmd_time( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ else if ( ! strcmp( str, "response" ) )
+ {
+ long l;
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < 0 || l > 1000 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ time_response = (unsigned int)l;
+ return 1;
+ }
+ else if ( ! strcmp( str, "remain" ) )
+ {
+ long l1, l2;
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l1 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l1 == LONG_MAX || l1 < 0 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l2 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l2 == LONG_MAX || l2 < 0 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ if ( sec_limit_up == UINT_MAX )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ return reset_time( (unsigned int)l1, (unsigned int)l2 );
+ }
+
+ str_error = str_bad_cmdline;
+ return -2;
+}
+
+
+#if !defined(MINIMUM)
+/* learn (ini|no-ini) steps games iterations tlp1 tlp2 */
+static int
+cmd_learn( tree_t * restrict ptree, char **lasts )
+{
+ const char *str1 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str2 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str3 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str4 = strtok_r( NULL, str_delimiters, lasts );
+# if defined(TLP)
+ const char *str5 = strtok_r( NULL, str_delimiters, lasts );
+ const char *str6 = strtok_r( NULL, str_delimiters, lasts );
+# endif
+ char *ptr;
+ long l;
+ unsigned int max_games;
+ int is_ini, nsteps, max_iterations, nworker1, nworker2, iret;
+
+ if ( str1 == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ if ( ! strcmp( str1, "ini" ) ) { is_ini = 1; }
+ else if ( ! strcmp( str1, "no-ini" ) ) { is_ini = 0; }
+ else {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ max_games = UINT_MAX;
+ max_iterations = INT_MAX;
+ nworker1 = nworker2 = nsteps = 1;
+
+ if ( str2 != NULL )
+ {
+ l = strtol( str2, &ptr, 0 );
+ if ( ptr == str2 || l == LONG_MAX || l < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ nsteps = (int)l;
+ }
+
+ if ( str3 != NULL )
+ {
+ l = strtol( str3, &ptr, 0 );
+ if ( ptr == str3 || l == LONG_MAX || l == LONG_MIN )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ if ( l > 0 ) { max_games = (unsigned int)l; }
+ }
+
+ if ( str4 != NULL )
+ {
+ l = strtol( str4, &ptr, 0 );
+ if ( ptr == str4 || l == LONG_MAX || l == LONG_MIN )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ if ( l > 0 ) { max_iterations = (int)l; }
+ }
+
+# if defined(TLP)
+ if ( str5 != NULL )
+ {
+ l = strtol( str5, &ptr, 0 );
+ if ( ptr == str5 || l > TLP_MAX_THREADS || l < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ nworker1 = (int)l;
+ }
+
+ if ( str6 != NULL )
+ {
+ l = strtol( str6, &ptr, 0 );
+ if ( ptr == str6 || l > TLP_MAX_THREADS || l < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ nworker2 = (int)l;
+ }
+# endif
+
+ AbortDifficultCommand;
+
+ log2_ntrans_table = 12;
+
+ memory_free( (void *)ptrans_table_orig );
+
+ iret = ini_trans_table();
+ if ( iret < 0 ) { return iret; }
+
+ iret = learn( ptree, is_ini, nsteps, max_games, max_iterations,
+ nworker1, nworker2 );
+ if ( iret < 0 ) { return -1; }
+
+ iret = ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL );
+ if ( iret < 0 ) { return -1; }
+
+ iret = get_elapsed( &time_turn_start );
+ if ( iret < 0 ) { return iret; }
+
+ return 1;
+}
+#endif /* MINIMUM */
+
+
+#if defined(MPV)
+static int
+cmd_mpv( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long l;
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ else if ( ! strcmp( str, "num" ) )
+ {
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < 1 || l > MPV_MAX_PV )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ AbortDifficultCommand;
+
+ mpv_num = (int)l;
+
+ return 1;
+ }
+ else if ( ! strcmp( str, "width" ) )
+ {
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < MT_CAP_PAWN )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ AbortDifficultCommand;
+
+ mpv_width = (int)l;
+
+ return 1;
+ }
+
+ str_error = str_bad_cmdline;
+ return -2;
+}
+#endif
+
+
+#if defined(TLP)
+static int
+cmd_thread( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ else if ( ! strcmp( str, "num" ) )
+ {
+ char *ptr;
+ long l;
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < 1 || l > TLP_MAX_THREADS )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ TlpEnd();
+
+ tlp_max = (int)l;
+
+ if ( game_status & ( flag_thinking | flag_pondering | flag_puzzling ) )
+ {
+ return tlp_start();
+ }
+ return 1;
+ }
+
+ str_error = str_bad_cmdline;
+ return -2;
+}
+#endif
+
+
+#if defined(CSA_LAN)
+static int
+cmd_connect( tree_t * restrict ptree, char **lasts )
+{
+ const char *str;
+ char *ptr;
+ long max_games;
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str || ! strcmp( str, "." ) ) { str = "gserver.computer-shogi.org"; }
+ strncpy( client_str_addr, str, 255 );
+ client_str_addr[255] = '\0';
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str || ! strcmp( str, "." ) ) { str = "4081"; }
+ client_port = strtol( str, &ptr, 0 );
+ if ( ptr == str || client_port == LONG_MAX || client_port < 0
+ || client_port > USHRT_MAX )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza_test"; }
+ strncpy( client_str_id, str, 255 );
+ client_str_id[255] = '\0';
+
+ str = strtok_r( NULL, " \t", lasts );
+ if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza_test"; }
+ strncpy( client_str_pwd, str, 255 );
+ client_str_pwd[255] = '\0';
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str || ! strcmp( str, "." ) ) { client_max_game = INT_MAX; }
+ else {
+ max_games = strtol( str, &ptr, 0 );
+ if ( ptr == str || max_games == LONG_MAX || max_games < 1 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ client_max_game = max_games;
+ }
+
+ AbortDifficultCommand;
+
+ client_ngame = 0;
+
+ return client_next_game( ptree, client_str_addr, (int)client_port );
+}
+#endif
+
+
+#if defined(MNJ_LAN)
+static int
+cmd_mnj( tree_t * restrict ptree, char **lasts )
+{
+ char client_str_addr[256];
+ char client_str_id[256];
+ const char *str;
+ char *ptr;
+ unsigned int seed;
+ int sd;
+ long l;
+ int client_port;
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < 0 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ sd = (int)l;
+
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < 0 )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ seed = (unsigned int)l;
+
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str || ! strcmp( str, "." ) ) { str = "localhost"; }
+ strncpy( client_str_addr, str, 255 );
+ client_str_addr[255] = '\0';
+
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str || ! strcmp( str, "." ) ) { str = "4082"; }
+ l = strtol( str, &ptr, 0 );
+ if ( ptr == str || l == LONG_MAX || l < 0 || l > USHRT_MAX )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ client_port = (int)l;
+
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza1"; }
+ strncpy( client_str_id, str, 255 );
+ client_str_id[255] = '\0';
+
+ AbortDifficultCommand;
+
+ resign_threshold = 65535;
+ game_status |= ( flag_noponder | flag_noprompt );
+ if ( mnj_reset_tbl( sd, seed ) < 0 ) { return -1; }
+
+ sckt_mnj = sckt_connect( client_str_addr, (int)client_port );
+ if ( sckt_mnj == SCKT_NULL ) { return -2; }
+
+ str_buffer_cmdline[0] = '\0';
+
+ Out( "Sending my name %s", client_str_id );
+ sckt_out( sckt_mnj, "%s\n", client_str_id );
+
+ return analyze( ptree );
+}
+#endif
+
+
+#if defined(DEKUNOBOU)
+
+static int
+cmd_dek( char **lasts )
+{
+ const char *str = strtok_r( NULL, str_delimiters, lasts );
+ char *ptr;
+ long l1, l2;
+ int iret;
+
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ strncpy( str_message, str, SIZE_MESSAGE-1 );
+ str_message[SIZE_MESSAGE-1] = '\0';
+ dek_ul_addr = inet_addr( str );
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l1 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l1 == LONG_MAX || l1 < 0 || l1 > USHRT_MAX )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ str = strtok_r( NULL, str_delimiters, lasts );
+ if ( str == NULL )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+ l2 = strtol( str, &ptr, 0 );
+ if ( ptr == str || l2 == LONG_MAX || l2 < 0 || l2 > USHRT_MAX )
+ {
+ str_error = str_bad_cmdline;
+ return -2;
+ }
+
+ AbortDifficultCommand;
+
+ iret = dek_start( str_message, (int)l1, (int)l2 );
+ if ( iret < 0 ) { return iret; }
+
+ Out( "\n- in communication with Dekunobou...\n" );
+
+ str_buffer_cmdline[0] = '\0';
+ dek_ngame = 1;
+ dek_lost = 0;
+ dek_win = 0;
+ dek_turn = 1;
+ game_status |= flag_resigned;
+
+ return 1;
+}
+
+#endif
+
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include "shogi.h"
+
+/* #define DBG_QSEARCH */
+#if defined(DBG_QSEARCH)
+# define DOut( ... ) if ( dbg_flag ) { out( __VA_ARGS__ ); }
+#else
+# define DOut( ... )
+#endif
+
+static int gen_next_quies( tree_t * restrict ptree, int alpha, int turn,
+ int ply, int qui_ply );
+
+int
+search_quies( tree_t * restrict ptree, int alpha, int beta, int turn, int ply,
+ int qui_ply )
+{
+ int value, alpha_old;
+
+#if defined(DBG_QSEARCH)
+ int dbg_flag = 0;
+
+ if ( iteration_depth == 2 && ply == 4
+ && ! strcmp( str_CSA_move(ptree->current_move[1]), "7776FU" )
+ && ! strcmp( str_CSA_move(ptree->current_move[2]), "3334FU" )
+ && ! strcmp( str_CSA_move(ptree->current_move[3]), "8822UM" ) )
+ {
+ dbg_flag = 1;
+ Out( "qsearch start (alpha=%d beta=%d sp=%d %" PRIu64 ")",
+ alpha, beta, value, ptree->node_searched );
+ }
+#endif
+
+
+#if defined(TLP)
+ if ( ! ptree->tlp_id )
+#endif
+ {
+ node_last_check += 1;
+ }
+ ptree->node_searched += 1;
+ ptree->nquies_called += 1;
+ alpha_old = alpha;
+
+ value = evaluate( ptree, ply, turn );
+
+
+ if ( alpha < value )
+ {
+ if ( beta <= value )
+ {
+ DOut( ", cut by stand-pat\n" );
+ MOVE_CURR = MOVE_PASS;
+ return value;
+ }
+ alpha = value;
+ }
+
+ if ( ply >= PLY_MAX-1 )
+ {
+ if ( alpha_old != alpha ) { pv_close( ptree, ply, no_rep ); }
+ MOVE_CURR = MOVE_NA;
+ return value;
+ }
+
+
+ if ( ( qui_ply == 1 && ! ( ply == 2 && InCheck( turn ) ) )
+ || ( 1 < qui_ply && qui_ply < QUIES_PLY_LIMIT && ! InCheck( turn ) ) )
+ {
+ MOVE_CURR = IsMateIn1Ply( turn );
+ if ( MOVE_CURR )
+ {
+ value = score_mate1ply + 1 - ply;
+
+ if ( alpha < value
+ && value < beta ) { pv_close( ptree, ply, mate_search ); }
+
+ DOut( "mate found\n" );
+
+ assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+ return value;
+ }
+ }
+
+
+ ptree->anext_move[ply].next_phase = next_quies_gencap;
+ while ( gen_next_quies( ptree, alpha, turn, ply, qui_ply ) )
+ {
+ DOut( "\nexpand %s (%" PRIu64 ")",
+ str_CSA_move(MOVE_CURR), ptree->node_searched );
+
+ MakeMove( turn, MOVE_CURR, ply );
+ if ( InCheck(turn) )
+ {
+ UnMakeMove( turn, MOVE_CURR, ply );
+ continue;
+ }
+
+ value = -search_quies( ptree, -beta, -alpha, Flip(turn), ply+1,
+ qui_ply+1 );
+
+ UnMakeMove( turn, MOVE_CURR, ply );
+
+ if ( alpha < value )
+ {
+ check_futile_score_quies( ptree, MOVE_CURR, ptree->stand_pat[ply],
+ -ptree->stand_pat[ply+1], turn );
+ if ( beta <= value )
+ {
+ DOut( ", beta cut (%" PRIu64 ")\n", ptree->node_searched );
+
+ assert( ! IsMove(MOVE_CURR)
+ || is_move_valid( ptree, MOVE_CURR, turn ) );
+ return value;
+ }
+
+ DOut( ", renew alpha=%d (%" PRIu64 ")\n",
+ value, ptree->node_searched );
+ alpha = value;
+ }
+ }
+
+ DOut( "\nall searched (%" PRIu64 ")\n", ptree->node_searched );
+
+ if ( qui_ply < QUIES_PLY_LIMIT && is_mate_in3ply( ptree, turn, ply ) )
+ {
+ value = score_mate1ply + 1 - ply;
+
+ if ( alpha < value
+ && value < beta ) { pv_close( ptree, ply, mate_search ); }
+
+ assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+ return value;
+ }
+
+ if ( alpha_old != alpha )
+ {
+ if ( alpha == ptree->stand_pat[ply] ) { pv_close( ptree, ply, no_rep ); }
+ else { pv_copy( ptree, ply ); }
+ }
+
+ return alpha;
+}
+
+
+static int
+gen_next_quies( tree_t * restrict ptree, int alpha, int turn, int ply,
+ int qui_ply )
+{
+ switch ( ptree->anext_move[ply].next_phase )
+ {
+ case next_quies_gencap:
+ {
+ unsigned int * restrict pmove;
+ int * restrict psortv;
+ int i, j, n, nqmove, value, min_score, diff;
+ unsigned int move;
+
+ ptree->move_last[ply] = GenCaptures( turn, ptree->move_last[ply-1] );
+
+ /* set sort values */
+ pmove = ptree->move_last[ply-1];
+ psortv = ptree->sort_value;
+ nqmove = 0;
+ n = (int)( ptree->move_last[ply] - pmove );
+
+ for ( i = 0; i < n; i++ )
+ {
+ move = pmove[i];
+
+ if ( qui_ply >= QUIES_PLY_LIMIT
+ && ( ( UToCap(move) == pawn && ! I2IsPromote(move) )
+ || ( ! UToCap(move) && I2PieceMove(move) != pawn ) ) )
+ {
+ continue;
+ }
+
+ diff = estimate_score_diff( ptree, move, turn );
+ min_score = eval_max_score( ptree, move, ptree->stand_pat[ply],
+ turn, diff );
+
+ if ( alpha < min_score )
+ {
+ value = swap( ptree, move, -1, MT_CAP_SILVER, turn );
+ if ( -1 < value )
+ {
+ psortv[nqmove] = value + diff;
+ pmove[nqmove++] = move;
+ }
+ }
+ }
+
+ /* insertion sort */
+ psortv[nqmove] = INT_MIN;
+ for ( i = nqmove-2; i >= 0; i-- )
+ {
+ value = psortv[i]; move = pmove[i];
+ for ( j = i+1; psortv[j] > value; j++ )
+ {
+ psortv[j-1] = psortv[j]; pmove[j-1] = pmove[j];
+ }
+ psortv[j-1] = value; pmove[j-1] = move;
+ }
+
+ ptree->move_last[ply] = ptree->move_last[ply-1] + nqmove;
+ ptree->anext_move[ply].move_last = pmove;
+ ptree->anext_move[ply].next_phase = next_quies_captures;
+ }
+
+ case next_quies_captures:
+ if ( ptree->anext_move[ply].move_last != ptree->move_last[ply] )
+ {
+ MOVE_CURR = *ptree->anext_move[ply].move_last++;
+ return 1;
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+#include "shogi.h"
+
+/* PRNG based on Mersenne Twister (M. Matsumoto and T. Nishimura, 1998). */
+#define RAND_M 397
+#define MASK_U 0x80000000U
+#define MASK_L 0x7fffffffU
+#define MASK32 0xffffffffU
+
+void
+ini_rand( unsigned int u )
+{
+ int i;
+
+ rand_work.count = RAND_N;
+ rand_work.cnst[0] = 0;
+ rand_work.cnst[1] = 0x9908b0dfU;
+
+ u &= MASK32;
+ rand_work.vec[0] = u;
+ for ( i = 1; i < RAND_N; i++ )
+ {
+ u = i + 1812433253U * ( u ^ ( u >> 30 ) );
+ u &= MASK32;
+ rand_work.vec[i] = u;
+ }
+}
+
+
+unsigned int
+rand32( void )
+{
+ unsigned int u, u0, u1, u2;
+ int i;
+
+ if ( rand_work.count == RAND_N )
+ {
+ rand_work.count = 0;
+
+ for ( i = 0; i < RAND_N-RAND_M; i++ )
+ {
+ u = rand_work.vec[i] & MASK_U;
+ u |= rand_work.vec[i+1] & MASK_L;
+
+ u0 = rand_work.vec[ i + RAND_M ];
+ u1 = u >> 1;
+ u2 = rand_work.cnst[ u & 1 ];
+
+ rand_work.vec[i] = u0 ^ u1 ^ u2;
+ }
+
+ for ( ; i < RAND_N-1 ;i++ )
+ {
+ u = rand_work.vec[i] & MASK_U;
+ u |= rand_work.vec[i+1] & MASK_L;
+
+ u0 = rand_work.vec[ i + RAND_M - RAND_N ];
+ u1 = u >> 1;
+ u2 = rand_work.cnst[ u & 1 ];
+
+ rand_work.vec[i] = u0 ^ u1 ^ u2;
+ }
+
+ u = rand_work.vec[RAND_N-1] & MASK_U;
+ u |= rand_work.vec[0] & MASK_L;
+
+ u0 = rand_work.vec[ RAND_M - 1 ];
+ u1 = u >> 1;
+ u2 = rand_work.cnst[ u & 1 ];
+
+ rand_work.vec[RAND_N-1] = u0 ^ u1 ^ u2;
+ }
+
+ u = rand_work.vec[ rand_work.count++ ];
+ u ^= ( u >> 11 );
+ u ^= ( u << 7 ) & 0x9d2c5680U;
+ u ^= ( u << 15 ) & 0xefc60000U;
+ u ^= ( u >> 18 );
+
+ return u;
+}
+
+
+uint64_t
+rand64( void )
+{
+ uint64_t h = rand32();
+ uint64_t l = rand32();
+
+ return l | ( h << 32 );
+}
--- /dev/null
+----------------------------------------------------------------------
+ Bonanza Feliz 0.0 - Executable Source Code
+ Kunihito Hoki, 1 Apr 2010
+----------------------------------------------------------------------
+
+
+1. Introduction
+----------------
+
+Bonanza is a state-of-the art computer shogi engine which runs on
+Windows and Linux machines, and this directory contains a
+platform-independent source code.
+
+This source code is distributed with a hope that it will be useful in
+addition to the main part of the shogi engine. This program includes
+many useful functions such as manipulating a shogi board, reading and
+writing a CSA record file, speaking of a CSA protocol with a socket
+communication, and controlling time, and etc.. I believe this program
+can be a good starting point if you are interested in making shogi
+programs.
+
+One main feature of this program is that it employs a brute-force
+search method together with bitboard techniques as many chess programs
+do. Another notable feature is a machine learning of shogi evaluation
+functions. The details of the learning algorithm (aka Bonanza method)
+were already presented [1], and this source code provides an example
+of implementation of the learning method.
+
+I admit that some parts of the source code are cryptic, e.g. codes in
+"mate1ply.c". I hope that I will have some time to make a quality
+documentation and comments on the program code, or someone else could
+decrypt my program and provide a documentation.
+
+Any comments or suggestions are welcome [2].
+
+[1] K. Hoki, "Optimal control of minimax search results to learn
+ positional evaluation", Game Programming Workshop, Hakone, Japan
+ 2008.
+
+[2] Contact to "bonanza_query [at] hotmail.com".
+
+
+2. Legal Notices
+-----------------
+
+This program is protected by copyright. Without a specific
+permission, any means of commercial applications are prohibited.
+Furthermore, this program is distributed without any warranty.
+Within these limits, you can use, redistribute, and/or modify it.
+
+
+3. Change Logs
+---------------
+
+Feliz 0.0
+
+- Some results from Y. Sato's experiments with Bonanza inspired me
+ to use the history table in LMR in Shogi, as Fruit did in chess. By
+ doing so, some improvement in performance of the tree search is
+ made.
+
+- From private communications with Yaneurao, it turned out that the
+ 3-ply-mate detections in 'mate3.c' can search game trees more
+ efficiently by using several heuristic pruning techniques. Now
+ 'mate3.c' adopts some of these techniques.
+
+- E. Ito kindly reported two bugs in the source codes. One is in
+ hash_store(), and the other is in ehash_probe() and
+ ehash_store(). Now these are fixed.
+
+- The structure of history table is modified from 'square-to' and
+ 'square-from' method to an exact match method by using the perfect
+ hash technique. The hash function of moves in 'phash.c' is generated
+ by codes at http://burtleburtle.net/bob/hash/perfect.html.
+
+- A command 'mnj' is added to connect to the cluster-computing server
+ in src/cluster/.
+
+- In client_next_game(), the way of dealing with REJECT message from a
+ CSA Shogi server is revised. Now Bonanza connects to the server again
+ when the game is rejected by an opponent.
+
+
+Version 4.1.3
+- The owner of 'LS3600 Blog Webpage' pointed out that there were two
+ serious bugs. Thank you very much! According to his indication,
+ is_hand_eq_supe() in 'utility.c' and read_CSA_line() in 'csa.c' are
+ revised.
+- In MPV code in 'searchr.c', a test of 'root_abort' flag had been
+ forgotten. Now the flag is tested after every call of search().
+- 'lan.txt' is added to 'src/executable/' directory. This is an
+ example of an input sequence to connect to CSA Shogi server.
+- 'book.bin' now has smaller moves and positions than previous one does.
+ Also, 'book_anti.csa' is added to 'src/executable/' directory. This
+ is an example of bad moves which apear in records of human experts.
+- 'Legal Notices' in this document is corrected.
+
+Version 4.1.2
+- In 'Makefile' and 'Makefile.vs', targets which require profile-guided
+ optimization are removed. Furthermore, an option, which controls
+ optimization, has been reverted from the aggressive flag, -O3, to a
+ moderate one, '-O2'. These modifications were necessary for avoiding
+ abnormal terminations of the program.
+- In 'ini.c', the attribute of POSIX thread in a global-variable
+ 'pthread_attr' is set to 'detach-state'. Because threads will never
+ join with any other threads in this program, the thread should be
+ created in the detached state to free system resources.
+- In 'ini.c', the default size of the transposition table is lifted
+ from 12MByte to 48MByte.
+- In 'iterate.c", probing the opening book is avoided when the move
+ history of a current game has repetitions.
+- In 'shogi.h', the margins of futility pruning are increased in
+ accord with new positional evaluation of the feature vector in
+ 'fv.bin'.
+- The quality of an opening book, 'winbin/book.bin', has been improved
+ at the expense of quantity.
+
+Version 4.1.0 and 4.1.1 (26 Apr 2009)
+- In 'Makefile' and 'Makefile.vs', some options of Intel C compiler
+ are modified. Here, agressive optimization '-O3' is substituted for
+ the default '-O2', pthreads support '-pthread' is substituted for
+ '-lpthread', and an obsolete '-static-libcxx' is removed.
+- In 'Makefile', the conformance of GNU C and Intel C compilers are
+ set to GNU extensions of ISO C99 by setting '-std=gnu99' because a
+ POSIX function 'strtok_r()' is not in the C99 standard library.
+- In 'Makefile', targets for GNU C with gprof and profile-guided
+ optimization of GNU C are removed.
+- In 'shogi.h', inline assemblies and intrinsics are used on x86-64 as
+ well as x86. To detect the targets, pre-defined macros '__i386__'
+ and '__x86_64__' are examined.
+- In 'evaluate.c', the evaluation function looks up the table
+ 'stand_pat[ply]' to see if the position have been evaluated since
+ the previous move is made by 'make_move_[bw]()' functions. Also, the
+ evaluation function probes the hash table 'ehash_tbl[]' to avoid
+ re-evaluation of the same position.
+- In 'io.c', an immediate value 0 is substituted for 'fileno(stdin)'
+ because the POSIX function 'fileno()' is not part of ANSI C. POSIX
+ requires that the file descriptor associated with 'stdin' be 0.
+- In 'iterate.c', a criterion for aging of transposition-table, i.e.,
+ increment of a global variable 'trans_table_age', is lifted from 7%
+ to 9% of saturation ratio of the table.
+- In 'learn1.c', the macro 'SEARCH_DEPTH' is set to 2. The macro
+ specifies the depth threashold of searches for finding all of
+ principle variations of positions in a set of games.
+- In 'learn1.c', a step size of increment/decrement of feature vectors
+ is fixed to 1 in 'learn_parse2()' function.
+- In 'hash.c', when a node can be pruned by using a hash value based on
+ futility pruning, a return value of the node is set to beta.
+- In 'rand.c', some codes of initialization of PRNG variables are
+ moved to 'ini_genrand()' from 'ini()' function.
+- In 'sckt.c', a function 'send_crlf()' is removed.
+- In 'search.c', now 'search()' calls 'search_quies()' and returns if
+ a search depth reaches a threashold. So that we can call 'search()'
+ function anytime, and this makes source codes simple.
+- In 'search.c', the static evaluation value is evaluated and used to
+ see if the late-move reduction is applicable or not. The evaluation
+ value is also used by the futility pruning.
+- In 'search.c', the futility pruning is not applied if the node is in
+ check or the move is a check.
+- In 'search.c', now Bonanza sends the keep-alive command '0x0a' to
+ the server in 'detect_signals()'.
+- In 'time.c', 'set_seach_limit_time()' is simplified.
+- In 'time.c', the second argument of 'gettimeofday()' is set to 'NULL'.
+
+Version 4.0.4 (2 Feb 2009)
+- An error of GCC inline assembly for spinlock in "thread.c" is fixed.
+- In Windows OS, Bonanza now opens all streams with file sharing by
+ using "_SH_DENYNO" constant in "io.c".
+- GCC built-in functions are substituted for GCC inline assemblies for
+ bit-scan operations in "bitop.h". Furthermore, "bitop.h" is removed,
+ and some of macros in the header are integrated into "shogi.h".
+
+Version 4.0.3 (Jan 2008)
+
+
+4. Files
+---------
+
+Here is a list of files you can find in this directory.
+
+C headers
+- param.h piece values
+- shogi.h main header
+
+basic C functions
+- main.c main function of C program
+- data.c definition of global variables
+- ini.c initializations
+- rand.c pseudo random number generator
+- time.c time functions
+- bitop.c bit operation
+- utility.c misc. functions
+
+I/O
+- proce.c input procedure
+- csa.c csa file format I/O
+- io.c basic I/O
+- dek.c dekunobou
+- sckt.c TCP/IP client of CSA SHOGI protocol
+
+bitboard manipulations
+- attack.c piece attacks
+- genchk.c move generation (checks)
+- genevasn.c move generation (evasions)
+- gendrop.c move generation (drops)
+- gennocap.c move generation (non-captures)
+- gencap.c move generation (captures)
+- movgenex.c move generation (inferior moves)
+- makemove.c make moves
+- unmake.c unmake move
+- mate1ply.c 1-ply mate detection
+- debug.c examine bitboard validity
+
+brute-force search
+- iterate.c iterative deepning search at root node
+- searchr.c alpha-beta search at root node
+- search.c alpha-beta search
+- next.c obtains next move
+- quiesrch.c quiescence search
+- evaluate.c static eveluation function
+- evaldiff.c easy and fast evaluation function
+- swap.c static exchange evaluation
+- hash.c transposition table
+- thread.c thread-level parallelization
+- root.c root move genelation and shallow min-max search
+- mate3.c 3-ply mate detection
+- ponder.c pondering
+- book.c creates and probes opening book
+- problem.c auto problem solver
+- valid.c examine move validity
+
+optimal control of min-max search
+- learn1.c main functions
+- learn2.c feture vector manipuration
+
+misc.
+- bonanza.txt which now you are looking at
+- Makefile makefile for gnu make.exe
+- Makefile.vs makefile for Microsoft nmake.exe
+- bonanza.ico icon file for windows
+- bonanza.rc resource-definition file for windows
+- lan.txt example of input sequence to connect CSA Shogi server
+- book_anti.csa example of a set of bad moves which apear in records
+ of human exparts. This is used by 'book create' command.
+
+4. How to build Bonanza
+-----------------------
+
+You can build Bonanza by means of GNU Make on Linux or Microsoft NMAKE
+on Windows. Here is some examples:
+
+- GCC on Linux
+> make -f Makefile gcc
+
+- Intel C++ Compiler on Linux
+> make -f Makefile icc
+
+- Microsoft C/C++ Compiler on Windows
+> nmake -f Makefile.vs cl
+
+- Intel C++ Compiler on Windows
+> nmake -f Makefile.vs icl
+
+The C source codes are written by using ANSI C plus a small number of
+new features in ISO C99. Therefore, I think this can be easily built
+in many platforms without much effort.
+
+It may be necessary to define some macros in Makefile or
+Makefile.vs. The macros are:
+
+- NDEBUG (DEBUG) builds release (debug) version of Bonanza
+
+- MINIMUM disables some auxiliary functions that are not
+ necessary to play a game, e.g., book composition
+ and optimization of evaluation functions
+
+- TLP enables thread-level parallel search
+
+- MPV enables multi-PV search
+
+- CSA_LAN enables Bonanza to communicate by CSA Shogi TCP/IP
+ protcol
+
+- DEKUNOBOU enables dekunobou interface (available only for
+ Windows)
+
+- CSASHOGI builds an engine for CSA Shogi (available only for
+ Windows)
+
+- NO_LOGGING suppresses dumping log files
+
+Bonanza is an application that does not provide graphical user
+interface. If you could build "bonanza.exe" properly without CSASHOGI
+macro, it shows a prompt "Black 1>" when you execute it at a computer
+console.
+
+Bonanza uses three binary files: a feature vector of static evaluation
+function "fv.bin", an opening book "book.bin", and a
+position-learning database "hash.bin". You can find these in "winbin/"
+directory. Without the NO_LOGGING option, Bonanza must find "log/"
+directory to dump log files.
+
+
+5. Command List
+---------------
+
+- beep on
+- beep off
+ These commands enable (on) or disable (off) a beep when Bonanza
+ makes a move. The default is on.
+
+- book on
+- book off
+ These commands enable (on) or disable (off) to probe the opening
+ book, "./book.bin". The default is on.
+
+- book narrow
+- book wide
+ When the command with "narrow" is used, Bonanza selects a book
+ move from a small set of opening moves. The default is "wide". The
+ narrowing of the opening moves is useful if you want Bonanza
+ choose a common opening line.
+
+- book create
+ This command creates the opening book file, "./book.bin", by using
+ numerous experts' games in a single CSA record file, "./book.csa".
+ It also uses another CSA record file, "book_anti.csa", where you
+ can register bad moves that may appear in the experts' games at
+ the last moves in the record file. Here is the example:
+
+ ----------------------------------------
+ PI, +, +6978KI, %TORYO
+ /
+ PI, +, +6978KI, -8384FU, %TORYO
+ /
+ PI, +, +7776FU, -4132KI, %TORYO
+ /
+ PI, +, +7776FU, -4132KI, +2726FU, %TORYO
+ ----------------------------------------
+
+ This command becomes effective when MINIMUM macro is not defined
+ in the Makefile.
+
+- connect 'addr' 'port' 'id' 'passwd' ['ngame']
+ This command connects Bonanza to a shogi server by using the CSA
+ protocol. The first four arguments specify the network address,
+ port number, user ID, and password, respectively. The last
+ argument limits a number of games that will be played by Bonanza.
+ This command becomes effective when CSA_LAN macro is defined in
+ the Makefile.
+
+- dekunobou 'addr' 'port-dekunobou' 'port-bonanza'
+ This command connects Bonanza to Dekunobou.
+
+- display ['num']
+ This command prints the shogi board. If you want to flip the
+ board, set 'num' to 2. If not, set it to 1.
+
+- s
+ Bonanza makes a prompt reply while thinking as soon as this
+ command is used.
+
+- hash 'num'
+ This command is used to initialize the transposition table and
+ set the size of the table to 2^'num'.
+
+- hash learn create
+ This command is used to make a zero-filled position-lerning
+ database, "hash.bin". This command becomes effective when MINIMUM
+ macro is not defined in the Makefile.
+
+- hash learn on
+- hash learn off
+ These commands enable (on) or disable (off) the position learning.
+ The default is on.
+
+- learn 'str' 'steps' ['games' ['iterations' ['num1' ['num2']]]]
+ This command optimizes a feature vector of the static evaluation
+ function by using numorous experts' games in a single CSA record
+ file, "./records.csa". If you want to use a zero-filled vector as
+ an initial guess of the optimization procedure, set 'str' to
+ "ini". If not, set it to "no-ini". The third argument 'games' is a
+ number of games to be read from the record file. If the third
+ argument is negative or omitted, all games are read from the file.
+
+ The learning method iterates a set of procedures, and the number
+ of iteration can be limited by the fourth argument. It continues
+ as long as the argument is negative. The procedures consist of two
+ parts. The first part reads the record file and creates principal
+ variations by using 'num1' threads. The default value of 'num1' is
+ 1. The second part renews the feature vector 'steps' times by using
+ 'num2' threads in accord with the principal variations. The default
+ value of 'steps' and 'num2' is 1. Note that each thread in the
+ second procedure uses about 500MByte of the main memory. The two
+ arguments 'num1' and 'num2' become effective when TLP macro is
+ defined in the Makefile. After the procedures, the optimized
+ vector is saved in "./fv.bin". This command become effective when
+ MINIMUM macro is not defined in the Makefile.
+
+- limit depth 'num'
+ This command is used to specify a depth, 'num', at which Bonanza
+ ends the iterative deepening search.
+
+- limit nodes 'num'
+ When this command is used, Bonanza stops thinking after searched
+ nodes reach to 'num'.
+
+- limit time 'minute' 'second' ['depth']
+ This command limits thinking time of Bonanza. It tries to make
+ each move by consuming the time 'minute'. When the time is spent
+ all, it makes each move in 'second'. The last argument 'depth' can
+ be used if you want Bonanza to stop thinking after the iterative
+ deepening searches reach sufficient depth.
+
+- limit time extendable
+- limit time strict
+ The command, "limit time extendable", allows Bonanza to think
+ longer than the time limited by the previous command if it wishes
+ to. The default is "strict".
+
+- mnj 'sd' 'seed' 'addr' 'port' 'id'
+ This command connects Bonanza to the council server in
+ src/cluster/. The first two integers specify the standard
+ deviation and initial seed of pseudo-random numbers which are
+ added to the static evaluation function. Experiments suggested
+ that an appropriate value for the standard deviation is 50. Note
+ that all clients should use different seeds. The last three
+ arguments are network address, port number, user ID,
+ respectively. This command becomes effective when MNJ_LAN macro is
+ defined in the Makefile.
+
+- move ['str']
+ Bonanza makes a move of 'str'. If the argument is omitted, Bonanza
+ thinks of its next move by itself.
+
+- mpv num 'nroot'
+- mpv width 'threshold'
+ These commands control the number of root moves, 'nroot', to
+ constitute principal variations. The default number is 1. A root
+ move that yields a smaller value than the best value by 'threshold'
+ is neglected. The default threshold is about 200. These commands
+ become effective when MPV macro is defined in the Makefile.
+
+- new ['str']
+ This command initializes the shogi board. The argument 'str'
+ controls an initial configuration of the board. If you want to
+ play a no-handicapped game, set 'str' to "PI" and this is the
+ default value. In a handicapped game, specify squares and pieces
+ to drop, e.g. "new PI82HI22KA" or "new PI19KY".
+
+- peek on
+- peek off
+ The command "peek on (off)" enables (disables) peeks at a buffer
+ of the standard input file while Bonanza is thinking. The default
+ is on. This command is useful when you want to process a set of
+ commands as "> ./bonanza.exe < infile".
+
+- ping
+ Prompt Bonanza to print "pong".
+
+- ponder on
+- ponder off
+ The command "ponder on (off)" enables (disables) thinks on the
+ opponent's time. The default is on.
+
+- problem ['num']
+ This command is used to solve problems in "./problem.csa". Here
+ is an example of the problem file.
+
+ -----------------------------
+ $ANSWER:+0024FU
+ P1-KY-KE-OU-KI * * * * -KY
+ P2 * * * * * -KI * * *
+ P3 * * -FU-GI-FU * -KE * -KA
+ P4-FU * * -FU-GI-FU-HI * -FU
+ P5 * * * * * * * -FU+KY
+ P6+FU+KA+FU+FU+GI+FU+KI * *
+ P7 * +FU * * +FU * * * *
+ P8 * +OU+KI+GI * * +HI * *
+ P9+KY+KE * * * * * +KE *
+ P+00FU00FU
+ P-00FU00FU00FU
+ +
+ /
+ $ANSWER:+0087KY:+0088KY
+ P1-OU-KE * * * * * +GI *
+ P2-KY-KI * * * * * * *
+ P3-FU-HI * -KI * * -GI * *
+ P4 * * -KE * * * * * -FU
+ P5 * +GI * -FU-FU-FU-FU-FU *
+ P6+FU+HI-FU * * * * * *
+ P7 * * * +FU * * * * +FU
+ P8 * * +OU+KI+KI * * * *
+ P9+KY+KE * * * * * +KE+KY
+ P+00KA00GI00KY00FU00FU
+ P-00KA00FU00FU00FU00FU00FU
+ +
+ -----------------------------
+
+ The argument 'num' specifies the number of problems to solve.
+
+- quit
+ The quit command and EOF character will exit Bonanza.
+
+- read 'filename' [(t|nil) ['num']]
+ This command is used to read a CSA record 'filename' up to 'num'
+ moves. Set the second argument to "nil" when you want to ignore
+ time information in the record. The default value is "t". Bonanza
+ reads all move sequence if the last argument is neglected. If
+ 'filename' is ".", the command reads an ongoing game from the
+ initial position.
+
+- resign
+ Use this command when you resign a game.
+
+- resign 'num'
+ This command specifies the threshold to resign. 'num' is a value
+ of the threshold. The default is around 1000.
+
+- stress on
+- stress off
+ When the command "stress on" is used, last-move shown in shogi
+ board is stressed. The default is on.
+
+- time remain 'num1' 'num2'
+ This command tells Bonanza the remaining time. 'num1' ('num2') is
+ the remaining time of black (white) in seconds.
+
+- time response 'num'
+ This command specifies a margin to control time. The time margin
+ saves Bonanza from time up due to TCP/IP communication to a server
+ program, sudden disc access, or imperfection of time control of
+ Bonanza. 'num' is the time margin in milli-second. The default
+ value is 200.
+
+- tlp 'num'
+ This command controls the number of threads to be created when
+ Bonana considers a move to make. The command becomes effective
+ when TLP macro is defined in the Makefile. 'num' is the number of
+ threads. The default value is 1.
+
+- #
+ A line beginning with # causes all characters on that line
+ to be ignored.
+
+- [move command]
+ A move command consists of four digits followed by two
+ capital alphabets, e.g. 7776FU. The first two digits
+ are a starting square and the last two are a target square. The
+ starting square is "OO" if the move is a dorp, e.g. 0087FU. The
+ following two alphabets specify a piece type as the following,
+
+ FU - pawn (Fuhyo) TO - promoted pawn (Tokin)
+ KY - lance (Kyousha) NY - promoted lance (Narikyo)
+ KE - knight (Keima) NK - promoted knight (Narikei)
+ GI - silver general (Ginsho) NG - promoted silver (Narigin)
+ KI - gold general (Kinsyo)
+ KA - Bishop (Kakugyo) UM - Dragon horse (Ryuma)
+ HI - Rook (Hisha) RY - Dragon king (Ryuo)
+ OU - King (Osho)
+
+ Here, words in parentheses are romanization of Japanese words.
--- /dev/null
+#include <stdlib.h>
+#include <limits.h>
+#include "shogi.h"
+
+static int read_rest_list( tree_t * restrict ptree,
+ unsigned int * restrict pmove_list );
+
+static int is_move_rest( unsigned int move,
+ const unsigned int * restrict pmove_restraint );
+
+int
+make_root_move_list( tree_t * restrict ptree, int flag )
+{
+ unsigned int * restrict pmove;
+ unsigned int arestraint_list[ MAX_LEGAL_MOVES ];
+ int asort[ MAX_LEGAL_MOVES ];
+ unsigned int move, move_best;
+ int i, j, k, h, value, num_root_move, iret, value_pre_pv;
+ int value_best;
+
+ if ( flag & flag_refer_rest ) { read_rest_list( ptree, arestraint_list ); }
+ else { arestraint_list[0] = 0; }
+
+ pmove = ptree->move_last[0];
+ ptree->move_last[1] = GenCaptures( root_turn, pmove );
+ ptree->move_last[1] = GenNoCaptures( root_turn, ptree->move_last[1] );
+ ptree->move_last[1] = GenDrop( root_turn, ptree->move_last[1] );
+ num_root_move = (int)( ptree->move_last[1] - pmove );
+
+ value_pre_pv = INT_MIN;
+ move_best = 0;
+ value_best = 0;
+ for ( i = 0; i < num_root_move; i++ )
+ {
+ if ( ! ( game_status & flag_nopeek )
+ && ( game_status & ( flag_puzzling | flag_pondering ) )
+ && i != 0
+ && ( i % 8 ) == 0 )
+ {
+ iret = next_cmdline( 0 );
+ if ( iret == -1 )
+ {
+ game_status |= flag_search_error;
+ return 1;
+ }
+ else if ( iret == -2 )
+ {
+ out_warning( "%s", str_error );
+ ShutdownClient;
+ }
+ else if ( game_status & flag_quit ) { return 1; }
+ else if ( iret )
+ {
+ iret = procedure( ptree );
+ if ( iret == -1 )
+ {
+ game_status |= flag_search_error;
+ next_cmdline( 1 );
+ return 1;
+ }
+ else if ( iret == -2 )
+ {
+ out_warning( "%s", str_error );
+ next_cmdline( 1 );
+ ShutdownClient;
+ }
+ else if ( iret == 1 ) { next_cmdline( 1 ); }
+
+ if ( game_status & ( flag_quit | flag_quit_ponder
+ | flag_suspend ) )
+ {
+ return 1;
+ }
+ }
+ }
+
+ value = INT_MIN;
+ move = pmove[i];
+
+ MakeMove( root_turn, move, 1 );
+ if ( ! InCheck( root_turn )
+ && ! is_move_rest( move, arestraint_list ) )
+ {
+ iret = no_rep;
+ if ( InCheck(Flip(root_turn)) )
+ {
+ ptree->nsuc_check[2]
+ = (unsigned char)( ptree->nsuc_check[0] + 1U );
+ if ( ptree->nsuc_check[2] >= 2 * 2 )
+ {
+ iret = detect_repetition( ptree, 2, Flip(root_turn), 2 );
+ }
+ }
+
+ if ( iret == perpetual_check ) { value = INT_MIN; }
+ else {
+ ptree->current_move[1] = move;
+ value = -search_quies( ptree, -score_bound, score_bound,
+ Flip(root_turn), 2, 1 );
+ if ( value > value_best )
+ {
+ value_best = value;
+ move_best = move;
+ }
+ if ( I2IsPromote(move) ) { value++; }
+ if ( move == ptree->pv[0].a[1] )
+ {
+ value_pre_pv = value;
+ value = INT_MAX;
+ }
+ }
+ }
+ UnMakeMove( root_turn, move, 1 );
+ asort[i] = value;
+ }
+ if ( UToCap(move_best) ) { root_move_cap = 1; }
+
+ /* shell sort */
+ for ( k = SHELL_H_LEN - 1; k >= 0; k-- )
+ {
+ h = ashell_h[k];
+ for ( i = num_root_move-h-1; i >= 0; i-- )
+ {
+ value = asort[i];
+ move = pmove[i];
+ for ( j = i+h; j < num_root_move && asort[j] > value; j += h )
+ {
+ asort[j-h] = asort[j];
+ pmove[j-h] = pmove[j];
+ }
+ asort[j-h] = value;
+ pmove[j-h] = move;
+ }
+ }
+
+ /* discard all of moves cause mate or perpetual check */
+ if ( asort[0] >= -score_max_eval )
+ {
+ for ( ; num_root_move; num_root_move-- )
+ {
+ if ( asort[num_root_move-1] >= -score_max_eval ) { break; }
+ }
+ }
+
+ /* discard perpetual checks */
+ else for ( ; num_root_move; num_root_move-- )
+ {
+ if ( asort[num_root_move-1] != INT_MIN ) { break; }
+ }
+
+ for ( i = 0; i < num_root_move; i++ )
+ {
+ root_move_list[i].move = pmove[i];
+ root_move_list[i].nodes = 0;
+ root_move_list[i].status = 0;
+ }
+ if ( value_pre_pv != INT_MIN ) { asort[0] = value_pre_pv; }
+ root_nmove = num_root_move;
+
+ if ( num_root_move > 1 && ! ( game_status & flag_puzzling ) )
+ {
+ int id_easy_move = 0;
+
+ if ( asort[0] > asort[1] + ( MT_CAP_DRAGON * 3 ) / 8 )
+ {
+ id_easy_move = 3;
+ easy_min = - ( MT_CAP_DRAGON * 4 ) / 16;
+ easy_max = ( MT_CAP_DRAGON * 32 ) / 16;
+ easy_abs = ( MT_CAP_DRAGON * 19 ) / 16;
+ }
+ else if ( asort[0] > asort[1] + ( MT_CAP_DRAGON * 2 ) / 8 )
+ {
+ id_easy_move = 2;
+ easy_min = - ( MT_CAP_DRAGON * 3 ) / 16;
+ easy_max = ( MT_CAP_DRAGON * 6 ) / 16;
+ easy_abs = ( MT_CAP_DRAGON * 9 ) / 16;
+ }
+ else if ( asort[0] > asort[1] + MT_CAP_DRAGON / 8
+ && asort[0] > - MT_CAP_DRAGON / 8
+ && I2From(pmove[0]) < nsquare )
+ {
+ id_easy_move = 1;
+ easy_min = - ( MT_CAP_DRAGON * 2 ) / 16;
+ easy_max = ( MT_CAP_DRAGON * 4 ) / 16;
+ easy_abs = ( MT_CAP_DRAGON * 6 ) / 16;
+ }
+
+ if ( easy_abs )
+ {
+ Out( "\n the root move %s looks easy (type %d).\n",
+ str_CSA_move(pmove[0]), id_easy_move );
+ Out( " evasion:%d, capture:%d, promotion:%d, drop:%d, "
+ "value:%5d - %5d\n",
+ ptree->nsuc_check[1] ? 1 : 0,
+ UToCap(pmove[0]) ? 1 : 0,
+ I2IsPromote(pmove[0]) ? 1 : 0,
+ I2From(pmove[0]) >= nsquare ? 1 : 0,
+ asort[0], asort[1] );
+ easy_value = asort[0];
+ }
+ }
+
+ return asort[0];
+}
+
+
+static int
+read_rest_list( tree_t * restrict ptree, unsigned int * restrict pmove_list )
+{
+ FILE *pf;
+ int iret, imove;
+ char a[65536];
+
+ pf = file_open( "restraint.dat", "r" );
+ if ( pf == NULL ) { return -2; }
+
+ for ( imove = 0; imove < MAX_LEGAL_MOVES; imove++ )
+ {
+#if defined(_MSC_VER)
+ iret = fscanf_s( pf, "%s\n", a, 65536 );
+#else
+ iret = fscanf( pf, "%s\n", a );
+#endif
+ if ( iret != 1 ) { break; }
+ iret = interpret_CSA_move( ptree, pmove_list+imove, a );
+ if ( iret < 0 )
+ {
+ file_close( pf );
+ return iret;
+ }
+ }
+
+ pmove_list[imove] = 0;
+
+ return file_close( pf );
+}
+
+
+static int
+is_move_rest( unsigned int move,
+ const unsigned int * restrict pmove_restraint )
+{
+ while ( *pmove_restraint )
+ {
+ if ( move == *pmove_restraint++ ) { return 1; }
+ }
+
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#if ! defined(_WIN32)
+# include <arpa/inet.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <unistd.h>
+#endif
+#include "shogi.h"
+
+#if defined(CSA_LAN) || defined(DEKUNOBOU) || defined(MNJ_LAN)
+const char *
+str_WSAError( const char *str )
+{
+# if defined(_WIN32)
+ snprintf( str_message, SIZE_MESSAGE, "%s:%d", str, WSAGetLastError() );
+ str_message[SIZE_MESSAGE-1] = '\0';
+ return str_message;
+# else
+ return str;
+# endif
+}
+#endif
+
+
+#if defined(CSA_LAN)
+int
+client_next_game( tree_t * restrict ptree, const char *str_addr, int iport )
+{
+ int iret;
+ int my_turn;
+ const char *str_name1, *str_name2;
+ char buf1[SIZE_PLAYERNAME], buf2[SIZE_PLAYERNAME];
+
+ for ( ;; ) {
+
+ str_buffer_cmdline[0] = '\0';
+ sckt_csa = sckt_connect( str_addr, iport );
+ if ( sckt_csa == SCKT_NULL ) { return -2; }
+
+ str_name1 = str_name2 = NULL;
+ iret = sckt_out( sckt_csa, "LOGIN %s %s\n",
+ client_str_id, client_str_pwd );
+ if ( iret < 0 ) { return iret; }
+
+ Out( "wait for next game-conditions...\n" );
+
+ my_turn = black;
+ for ( ;; ) {
+
+ iret = next_cmdline( 1 );
+ if ( iret < 0 ) { return iret; }
+ else if ( game_status & flag_quit ) { return 1; }
+
+ if ( ! strcmp( str_cmdline, "END Game_Summary" ) ) { break; }
+ else if ( ! strcmp( str_cmdline, "Your_Turn:-" ) ) { my_turn = white; }
+ else if ( ! memcmp( str_cmdline, "Name+:", 6 ) )
+ {
+ strncpy( buf1, str_cmdline+6, SIZE_PLAYERNAME-1 );
+ buf1[SIZE_PLAYERNAME-1] = '\0';
+ str_name1 = buf1;
+ }
+ else if ( ! memcmp( str_cmdline, "Name-:", 6 ) )
+ {
+ strncpy( buf2, str_cmdline+6, SIZE_PLAYERNAME-1 );
+ buf2[SIZE_PLAYERNAME-1] = '\0';
+ str_name2 = buf2;
+ }
+ }
+
+ iret = sckt_out( sckt_csa, "AGREE\n" );
+ if ( iret < 0 ) { return -2; }
+
+ iret = next_cmdline( 1 );
+ if ( iret < 0 ) { return iret; }
+ else if ( game_status & flag_quit ) { return 1; }
+
+ if ( ! memcmp( str_cmdline, "REJECT:", 7 ) )
+ {
+ ShutdownClient;
+ continue;
+ }
+ else if ( ! memcmp( str_cmdline, "START:", 6 ) ) { break; }
+
+ str_error = str_server_err;
+ return -2;
+ }
+
+ if ( ini_game( ptree, &min_posi_no_handicap, flag_history,
+ str_name1, str_name2 ) < 0 )
+ {
+ return -1;
+ }
+
+ if ( get_elapsed( &time_turn_start ) < 0 ) { return -1; }
+
+ client_turn = my_turn;
+ client_ngame += 1;
+
+ Out( "Game Conditions (%dth):\n", client_ngame );
+ Out( " my turn:%c\n", ach_turn[my_turn] );
+
+ if ( my_turn == root_turn )
+ {
+ iret = com_turn_start( ptree, 0 );
+ if ( iret < 0 ) { return iret; }
+ }
+
+ return 1;
+}
+#endif
+
+
+#if defined(CSA_LAN) || defined(MNJ_LAN)
+sckt_t
+sckt_connect( const char *str_addr, int iport )
+{
+ struct hostent *phe;
+ struct sockaddr_in sin;
+ sckt_t sd;
+ u_long ul_addr;
+
+#if defined(_WIN32)
+ {
+ WSADATA wsaData;
+ if ( WSAStartup( MAKEWORD(1,1), &wsaData ) )
+ {
+ str_error = str_WSAError( "WSAStartup() failed." );
+ return SCKT_NULL;
+ }
+ }
+#endif
+
+ ul_addr = inet_addr( str_addr );
+ if ( ul_addr == INADDR_NONE )
+ {
+ phe = gethostbyname( str_addr );
+ if ( ! phe )
+ {
+ str_error = str_WSAError( "gethostbyname() faild." );
+#if defined(_WIN32)
+ WSACleanup();
+#endif
+ return SCKT_NULL;
+ }
+ ul_addr = *( (u_long *)phe->h_addr_list[0] );
+ }
+
+ sd = socket( AF_INET, SOCK_STREAM, 0 );
+ if ( sd == SCKT_NULL )
+ {
+ str_error = str_WSAError( "socket() faild." );
+#if defined(_WIN32)
+ WSACleanup();
+#endif
+ return SCKT_NULL;
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ul_addr;
+ sin.sin_port = htons( (u_short)iport );
+ if ( connect( sd, (struct sockaddr *)&sin, sizeof(sin) ) == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "connect() faild." );
+#if defined(_WIN32)
+ WSACleanup();
+#endif
+ return SCKT_NULL;
+ }
+
+ return sd;
+}
+
+
+int
+sckt_shutdown( sckt_t sd )
+{
+ int iret;
+
+ if ( sd == SCKT_NULL ) { return 1; }
+ Out( "shut down connection\n" );
+
+# if defined(_WIN32)
+ if ( shutdown( sd, SD_SEND ) == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "shutdown() faild." );
+ WSACleanup();
+ return -2;
+ }
+
+ for ( ;; ) {
+ iret = recv( sd, str_message, SIZE_MESSAGE, 0 );
+ if ( iret == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "recv() failed." );
+ WSACleanup();
+ return -2;
+ }
+ else if ( ! iret ) { break; }
+ }
+
+ if ( closesocket( sd ) == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "closesocket() failed." );
+ WSACleanup();
+ return -2;
+ }
+
+ if ( WSACleanup() == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "WSACleanup() faild." );
+ return -2;
+ }
+
+ return 1;
+
+# else
+ if ( shutdown( sd, SHUT_RD ) == -1 )
+ {
+ str_error = "shutdown() faild.";
+ return -2;
+ }
+
+ for ( ;; ) {
+ iret = (int)recv( sd, str_message, SIZE_MESSAGE, 0 );
+ if ( iret == -1 )
+ {
+ str_error = "recv() failed.";
+ return -2;
+ }
+ else if ( ! iret ) { break; }
+ }
+
+ if ( close( sd ) == -1 )
+ {
+ str_error = "close() failed.";
+ return -2;
+ }
+
+ return 1;
+# endif
+}
+
+
+int
+sckt_check( sckt_t sd )
+{
+ struct timeval tv;
+ fd_set readfds;
+ int iret;
+
+ tv.tv_sec = tv.tv_usec = 0;
+
+ FD_ZERO( &readfds );
+# if defined(_MSC_VER)
+# pragma warning(disable:4127)
+# endif
+ FD_SET( sd, &readfds );
+# if defined(_MSC_VER)
+# pragma warning(default:4127)
+# endif
+
+ iret = select( (int)sd+1, &readfds, NULL, NULL, &tv );
+ if ( iret == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "select() with a socket connected failed." );
+ return -2;
+ }
+
+ return iret;
+}
+
+
+int
+sckt_in( sckt_t sd, char *str, int n )
+{
+ struct timeval tv;
+ fd_set readfds;
+ int iret;
+
+ for ( ;; ) {
+ Out( "wait for a message ... " );
+
+ tv.tv_sec = SEC_KEEP_ALIVE;
+ tv.tv_usec = 0;
+ FD_ZERO( &readfds );
+# if defined(_MSC_VER)
+# pragma warning(disable:4127)
+# endif
+ FD_SET( sd, &readfds );
+# if defined(_MSC_VER)
+# pragma warning(default:4127)
+# endif
+
+ iret = select( (int)sd+1, &readfds, NULL, NULL, &tv );
+ if ( iret == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "select() with a socket connected failed." );
+ return -1;
+ }
+ if ( iret )
+ {
+ Out( "done.\n" );
+ break;
+ }
+ Out( "time out.\n" );
+
+ if ( sckt_out( sd, "\n" ) == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "send() failed." );
+ return -1;
+ }
+ }
+
+ iret = recv( sd, str, n-1, 0 );
+ if ( iret == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "recv() failed." );
+ return -1;
+ }
+ *( str + iret ) = '\0';
+
+ if ( ! iret )
+ {
+ Out( "Connection closed.\n" );
+ return 0;
+ }
+
+ Out( "%s[END]\n", str );
+
+ return iret;
+}
+
+
+int
+sckt_out( sckt_t sd, const char *fmt, ... )
+{
+ int nch;
+ char buf[256];
+ va_list arg;
+
+ va_start( arg, fmt );
+ nch = vsnprintf( buf, 256, fmt, arg );
+ va_end( arg );
+ if ( nch >= 256 || nch < 0 )
+ {
+ str_error = "buffer overflow at sckt_out()";
+ return -1;
+ }
+
+ Out( "- now sending the message: %s", buf );
+
+ if ( send( sd, buf, nch, 0 ) == SOCKET_ERROR )
+ {
+ str_error = str_WSAError( "send() failed." );
+ return -1;
+ }
+
+ return get_elapsed( &time_last_send );
+}
+#endif /* CSA_LAN || MNJ_LAN */
+
--- /dev/null
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "shogi.h"
+
+static void hist_add( tree_t * restrict ptree, int ply );
+static void hist_good( tree_t * restrict ptree, unsigned int move, int ply,
+ int depth, int turn );
+static int detect_signals( tree_t * restrict ptree );
+static int detect_rep( tree_t * restrict ptree, int ply, int turn );
+static int rep_type( const tree_t * restrict ptree, int n, int i, int ply,
+ int turn );
+
+/* #define DBG_SEARCH */
+#if defined(DBG_SEARCH)
+# define DOut( ... ) if ( dbg_flag ) { out( __VA_ARGS__ ); }
+#else
+# define DOut( ... )
+#endif
+
+int
+search( tree_t * restrict ptree, int alpha, int beta, int turn, int depth,
+ int ply, unsigned int state_node )
+{
+ int value, alpha_old;
+
+ if ( ! ptree->nsuc_check[ply] && depth < PLY_INC )
+ {
+ return search_quies( ptree, alpha, beta, turn, ply, 1 );
+ }
+
+
+#if defined(DBG_SEARCH)
+ int dbg_flag = 0;
+ if ( iteration_depth == 3 && ply == 3
+ && ! strcmp( str_CSA_move(ptree->current_move[1]), "7776FU" )
+ && ! strcmp( str_CSA_move(ptree->current_move[2]), "3334FU" ) )
+ {
+ dbg_flag = 1;
+ Out( "search start (d%.1f %" PRIu64 ")\n",
+ (double)depth / (double)PLY_INC, ptree->node_searched );
+ }
+#endif
+
+ ptree->node_searched++;
+
+ if ( ply >= PLY_MAX-1 )
+ {
+ value = evaluate( ptree, ply, turn );
+ if ( alpha < value && value < beta ) { pv_close( ptree, ply, no_rep ); }
+ MOVE_CURR = MOVE_NA;
+ return value;
+ }
+
+
+#if ! defined(MINIMUM)
+ if ( ! ( game_status & flag_learning ) )
+#endif
+ {
+ /* check time and input */
+#if defined(TLP)
+ if ( ! ptree->tlp_id )
+#endif
+ if ( node_next_signal < ++node_last_check && detect_signals( ptree ) )
+ {
+ root_abort = 1;
+ return 0;
+ }
+
+ /* repetitions */
+ ptree->nrep_tried++;
+ switch ( detect_rep( ptree, ply, turn ) )
+ {
+ case black_superi_rep:
+ value = turn ? -score_inferior : score_inferior;
+ if ( alpha < value
+ && value < beta ) { pv_close( ptree, ply, black_superi_rep ); }
+ ptree->nsuperior_rep++;
+ MOVE_CURR = MOVE_NA;
+ return value;
+
+ case white_superi_rep:
+ value = turn ? score_inferior : -score_inferior;
+ if ( alpha < value
+ && value < beta ) { pv_close( ptree, ply, white_superi_rep ); }
+ ptree->nsuperior_rep++;
+ MOVE_CURR = MOVE_NA;
+ return value;
+
+ case four_fold_rep:
+ if ( alpha < score_draw
+ && score_draw < beta ) { pv_close( ptree, ply, four_fold_rep );}
+ ptree->nfour_fold_rep++;
+ MOVE_CURR = MOVE_NA;
+ return score_draw;
+
+ case perpetual_check:
+ ptree->nperpetual_check++;
+ MOVE_CURR = MOVE_NA;
+ return score_foul;
+
+ case perpetual_check2:
+ if ( ply > 4 )
+ {
+ ptree->nperpetual_check++;
+ MOVE_CURR = MOVE_NA;
+ return -score_foul;
+ }
+ break;
+ }
+
+ ptree->nreject_tried++;
+ if ( rejections_probe( ptree, turn, ply ) )
+ {
+ ptree->nreject_done++;
+ if ( alpha < score_inferior && score_inferior < beta )
+ {
+ pv_close( ptree, ply, turn ? white_superi_rep:black_superi_rep );
+ }
+ MOVE_CURR = MOVE_NA;
+ return score_inferior;
+ }
+ }
+
+ /*
+ no repetitions. worst situation of this node is checkmate,
+ and the best is to force checkmate within 1-ply.
+ */
+ alpha_old = alpha;
+ value = - ( score_mate1ply + 2 - ply );
+ if ( alpha < value )
+ {
+ if ( beta <= value )
+ {
+ MOVE_CURR = MOVE_NA;
+ return value;
+ }
+ alpha = value;
+ }
+ else {
+ value = score_mate1ply + 1 - ply;
+ if ( value <= alpha ) { return value; }
+ }
+
+#if defined(NO_NULL_PRUNE)
+ state_node &= ~node_do_null;
+#endif
+
+ ptree->amove_hash[ply] = 0;
+#if ! defined(MINIMUM)
+ if ( ! ( game_status & flag_learning ) )
+#endif
+ {
+ /* probe the transposition table */
+ int tv = hash_probe( ptree, ply, depth, turn, alpha, beta, state_node );
+ switch ( tv )
+ {
+ case value_exact:
+ if ( alpha < HASH_VALUE )
+ {
+ if ( HASH_VALUE < beta ) { pv_close( ptree, ply, hash_hit ); }
+ else {
+ MOVE_CURR = ptree->amove_hash[ply];
+ assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+ }
+ }
+ return HASH_VALUE;
+
+ case value_lower:
+ MOVE_CURR = ptree->amove_hash[ply];
+ assert( beta <= HASH_VALUE );
+ assert( ! IsMove(MOVE_CURR)
+ || is_move_valid( ptree, MOVE_CURR, turn ) );
+ if ( beta == alpha_old + 1 ) { return HASH_VALUE; }
+ break;
+
+ case value_upper:
+ assert( HASH_VALUE <= alpha );
+ if ( beta == alpha_old + 1 ) { return HASH_VALUE; }
+ break;
+
+ default:
+ state_node = tv;
+ }
+ }
+
+ DOut( "\nhash cut passed" );
+
+ if ( depth >= REJEC_MIN_DEPTH ) { add_rejections( ptree, turn, ply ); }
+
+
+ if ( ! ptree->nsuc_check[ply] )
+ {
+ /* detect a move mates in 3-ply */
+ if ( ( state_node & node_do_mate )
+ && is_mate_in3ply( ptree, turn, ply ) )
+ {
+ value = score_mate1ply + 1 - ply;
+
+ hash_store( ptree, ply, depth, turn, value_exact, value,
+ MOVE_CURR, 0 );
+
+ if ( alpha < value
+ && value < beta ) { pv_close( ptree, ply, mate_search ); }
+
+ if ( depth >= REJEC_MIN_DEPTH )
+ {
+ sub_rejections( ptree, turn, ply );
+ }
+ assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+ return value;
+ }
+
+
+ /* null move pruning */
+ if ( 2*PLY_INC <= depth
+ && ( state_node & node_do_null )
+ && beta == alpha_old + 1
+ && beta <= evaluate( ptree, ply, turn ) )
+ {
+ int null_depth, nrep;
+
+ null_depth = NullDepth(depth);
+ nrep = root_nrep + ply - 1;
+
+ MOVE_CURR = MOVE_PASS;
+ ptree->move_last[ply] = ptree->move_last[ply-1];
+ ptree->stand_pat[ply+1] = (short)( - ptree->stand_pat[ply] );
+ ptree->nsuc_check[ply+1] = 0;
+ ptree->rep_board_list[nrep] = HASH_KEY;
+ ptree->rep_hand_list[nrep] = HAND_B;
+ ptree->null_pruning_tried++;
+
+ value = -search( ptree, -beta, 1-beta, Flip(turn), null_depth, ply+1,
+ node_do_mate | node_do_recap | node_do_futile );
+ if ( SEARCH_ABORT )
+ {
+ if ( depth >= REJEC_MIN_DEPTH )
+ {
+ sub_rejections( ptree, turn, ply );
+ }
+ return 0;
+ }
+
+ if ( beta <= value )
+ {
+ ptree->null_pruning_done++;
+ if ( null_depth < PLY_INC )
+ {
+ hash_store( ptree, ply, depth, turn, value_lower,
+ value, MOVE_NA, state_node );
+ }
+ if ( depth >= REJEC_MIN_DEPTH )
+ {
+ sub_rejections( ptree, turn, ply );
+ }
+
+ DOut( "\nnull move cut!\n" );
+
+ assert( ! IsMove(MOVE_CURR)
+ || is_move_valid( ptree, MOVE_CURR, turn ) );
+ return value;
+ }
+
+ DOut( "\nnull passed" );
+
+ if ( value == - ( score_mate1ply - ply ) )
+ {
+ state_node |= node_mate_threat;
+ }
+ }
+ }
+
+ /* recursive iterative-deepening for pv nodes */
+ if ( ! ptree->amove_hash[ply]
+ && depth >= 3*PLY_INC
+ && ( ( alpha == root_alpha && beta == root_beta )
+ || ( alpha == -root_beta && beta == -root_alpha ) ) )
+ {
+ if ( depth >= REJEC_MIN_DEPTH ) { sub_rejections( ptree, turn, ply ); }
+ value = search( ptree, -score_bound, beta, turn, depth-2*PLY_INC, ply,
+ node_do_mate | node_do_recap );
+ if ( SEARCH_ABORT ) { return 0; }
+
+ if ( beta <= value && IsMove(MOVE_CURR) )
+ {
+ ptree->amove_hash[ply] = MOVE_CURR;
+ }
+ else if ( value < beta && ply <= (int)ptree->pv[ply-1].length )
+ {
+ assert( -score_bound < value );
+ ptree->amove_hash[ply] = ptree->pv[ply-1].a[ply];
+ }
+ assert( ! ptree->amove_hash[ply]
+ || is_move_valid( ptree, ptree->amove_hash[ply], turn ) );
+
+ if ( depth >= REJEC_MIN_DEPTH ) { add_rejections( ptree, turn, ply ); }
+ }
+
+ {
+ int depth_reduced, first_move_expanded, new_depth, extension;
+ int state_node_new;
+
+ ptree->move_last[ply] = ptree->move_last[ply-1];
+ ptree->anext_move[ply].next_phase = next_move_hash;
+ ptree->hist_nmove[ply] = 0;
+ first_move_expanded = 0;
+
+ evaluate( ptree, ply, turn );
+
+ /* expand all of off-springs */
+ while ( ptree->nsuc_check[ply]
+ ? gen_next_evasion( ptree, ply, turn )
+ : gen_next_move( ptree, ply, turn ) ) {
+
+ DOut( "\nexpand %s (%" PRIu64 ")",
+ str_CSA_move(MOVE_CURR), ptree->node_searched );
+
+ ptree->nsuc_check[ply+1] = 0U;
+ state_node_new = ( node_do_mate | node_do_recap | node_do_null
+ | node_do_futile );
+ extension = 0;
+ depth_reduced = 0;
+
+ hist_add( ptree, ply );
+
+ /* decision of extensions */
+ if ( turn ? is_move_check_w( ptree, MOVE_CURR )
+ : is_move_check_b( ptree, MOVE_CURR ) )
+ {
+ ptree->check_extension_done++;
+ ptree->nsuc_check[ply+1]
+ = (unsigned char)( ptree->nsuc_check[ply-1] + 1U );
+ extension = EXT_CHECK;
+ }
+ else if ( ptree->nsuc_check[ply]
+ && ptree->move_last[ply] - ptree->move_last[ply-1] == 1 )
+ {
+ ptree->onerp_extension_done++;
+ extension = EXT_ONEREP;
+ }
+ else if ( ! ptree->nsuc_check[ply]
+ && ( state_node & node_do_recap )
+ && I2To(MOVE_CURR) == I2To(MOVE_LAST)
+ && ( MOVE_CURR == ptree->anext_move[ply].move_cap1
+ || ( ( ptree->anext_move[ply].value_cap1
+ < ( ptree->anext_move[ply].value_cap2
+ + MT_CAP_PAWN ) )
+ && MOVE_CURR == ptree->anext_move[ply].move_cap2 ))
+ && ( UToCap(MOVE_LAST)
+ || ( I2IsPromote(MOVE_LAST)
+ && I2PieceMove(MOVE_LAST) != silver ) ) )
+ {
+ ptree->recap_extension_done++;
+ state_node_new = node_do_null | node_do_mate | node_do_futile;
+ if ( ! I2IsPromote(MOVE_CURR)
+ && I2PieceMove(MOVE_LAST) == UToCap(MOVE_LAST) )
+ {
+ extension = EXT_RECAP2;
+ }
+ else { extension = EXT_RECAP1; }
+ }
+
+ LimitExtension( extension, ply );
+
+ new_depth = depth + extension - PLY_INC;
+
+ /* reductions */
+ if ( PLY_INC <= new_depth
+ && ! ( state_node & node_mate_threat )
+ && ! ptree->nsuc_check[ply]
+ && ! UToCap(MOVE_CURR)
+ && ! ( I2IsPromote(MOVE_CURR) && I2PieceMove(MOVE_CURR) != silver )
+ && ptree->amove_hash[ply] != MOVE_CURR
+ && ptree->killers[ply].no1 != MOVE_CURR
+ && ptree->killers[ply].no2 != MOVE_CURR )
+ {
+ unsigned int key = phash( MOVE_CURR, turn );
+ unsigned int good = ptree->hist_good[key] + 1;
+ unsigned int triedx8 = ( ptree->hist_tried[key] + 2 ) * 8U;
+
+ if ( beta != alpha_old + 1 ) {
+
+ if ( good * 62U < triedx8 ) { depth_reduced = PLY_INC * 4/2; }
+ else if ( good * 46U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
+ else if ( good * 34U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
+ else if ( good * 19U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }
+
+ } else {
+
+ if ( good * 62U < triedx8 ) { depth_reduced = PLY_INC * 4/2; }
+ else if ( good * 46U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
+ else if ( good * 30U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
+ else if ( good * 12U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }
+ }
+
+ new_depth -= depth_reduced;
+ }
+
+ /* futility pruning */
+ if ( ! ptree->nsuc_check[ply+1]
+ && ! ptree->nsuc_check[ply]
+ && new_depth < 3*PLY_INC )
+ {
+ int diff = estimate_score_diff( ptree, MOVE_CURR, turn );
+ int bound = alpha;
+
+ if ( 2*PLY_INC <= new_depth ) { bound -= EFUTIL_MG2; }
+ else if ( 1*PLY_INC <= new_depth ) { bound -= EFUTIL_MG1; }
+
+ if ( eval_max_score( ptree, MOVE_CURR, ptree->stand_pat[ply],
+ turn, diff ) <= bound )
+ {
+ first_move_expanded += 1;
+ continue;
+ }
+ }
+
+ DOut( ", futil passed" );
+
+ MakeMove( turn, MOVE_CURR, ply );
+ if ( I2From(MOVE_CURR) < nsquare
+ && ! ptree->nsuc_check[ply]
+ && InCheck(turn) )
+ {
+ UnMakeMove( turn, MOVE_CURR, ply );
+ continue;
+ }
+
+ if ( ! ptree->nsuc_check[ply+1] && ! ptree->nsuc_check[ply] )
+ {
+ evaluate( ptree, ply+1, Flip(turn) );
+ assert( ptree->stand_pat[ply] != score_bound );
+
+ /* futility pruning */
+ if ( ( new_depth < PLY_INC && - ptree->stand_pat[ply+1] <= alpha )
+ || ( new_depth < 2*PLY_INC
+ && - ptree->stand_pat[ply+1] <= alpha - EFUTIL_MG1 )
+ || ( new_depth < 3*PLY_INC
+ && - ptree->stand_pat[ply+1] <= alpha - EFUTIL_MG2 ) )
+ {
+ first_move_expanded += 1;
+ UnMakeMove( turn, MOVE_CURR, ply );
+ continue;
+ }
+ }
+
+ if ( depth_reduced )
+ {
+ value = -search( ptree, -alpha-1, -alpha, Flip(turn), new_depth,
+ ply + 1, state_node_new );
+ if ( ! SEARCH_ABORT && alpha < value )
+ {
+ new_depth += depth_reduced;
+ value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+ ply+1, state_node_new );
+ }
+ }
+ else if ( ! first_move_expanded )
+ {
+ value = -search( ptree, -beta, -alpha, Flip(turn), new_depth, ply+1,
+ state_node_new );
+ }
+ else {
+ value = -search( ptree, -alpha-1, -alpha, Flip(turn), new_depth,
+ ply + 1, state_node_new );
+ if ( ! SEARCH_ABORT && alpha < value && beta != alpha+1 )
+ {
+ value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+ ply + 1, state_node_new );
+ }
+ }
+
+ if ( SEARCH_ABORT )
+ {
+ UnMakeMove( turn, MOVE_CURR, ply );
+ if ( depth >= REJEC_MIN_DEPTH )
+ {
+ sub_rejections( ptree, turn, ply );
+ }
+ return 0;
+ }
+
+ UnMakeMove( turn, MOVE_CURR, ply );
+
+ if ( alpha < value )
+ {
+ if ( new_depth < PLY_INC
+ && ! ptree->nsuc_check[ply+1]
+ && ptree->stand_pat[ply] != score_bound )
+ {
+ check_futile_score_quies( ptree, MOVE_CURR,
+ ptree->stand_pat[ply],
+ -ptree->stand_pat[ply+1], turn );
+ }
+
+ if ( beta <= value )
+ {
+ DOut( ", beta cut (%" PRIu64 ")\n", ptree->node_searched );
+
+ hash_store( ptree, ply, depth, turn, value_lower, value,
+ MOVE_CURR, state_node );
+ hist_good( ptree, MOVE_CURR, ply, depth, turn );
+
+ ptree->fail_high++;
+ if ( ! first_move_expanded ) { ptree->fail_high_first++; }
+
+ if ( depth >= REJEC_MIN_DEPTH )
+ {
+ sub_rejections( ptree, turn, ply );
+ }
+
+ assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+ return value;
+ }
+ }
+ if ( alpha < value ) { alpha = value; }
+
+ first_move_expanded += 1;
+#if defined(TLP)
+ if ( ! ( ptree->nsuc_check[ply]
+ && ptree->move_last[ply] - ptree->move_last[ply-1] < 4 )
+ && tlp_idle
+ && ( ( iteration_depth < 11 && PLY_INC * 3 <= depth )
+ || PLY_INC * 4 <= depth ) )
+ {
+ ptree->tlp_beta = (short)beta;
+ ptree->tlp_best = (short)alpha;
+ ptree->tlp_depth = (unsigned char)depth;
+ ptree->tlp_state_node = (unsigned char)state_node;
+ ptree->tlp_turn = (char)turn;
+ ptree->tlp_ply = (char)ply;
+ if ( tlp_split( ptree ) )
+ {
+ if ( SEARCH_ABORT ) { return 0; }
+ value = ptree->tlp_best;
+ if ( alpha < value )
+ {
+ if ( beta <= value )
+ {
+ if ( depth >= REJEC_MIN_DEPTH )
+ {
+ sub_rejections( ptree, turn, ply );
+ }
+
+ hash_store( ptree, ply, depth, turn, value_lower,
+ value, MOVE_CURR, state_node );
+
+ hist_good( ptree, MOVE_CURR, ply, depth, turn );
+
+ ptree->fail_high++;
+
+ assert( is_move_valid( ptree, MOVE_CURR, turn ) );
+ return value;
+ }
+ alpha = value;
+ }
+ break;
+ }
+ }
+#endif
+ }
+
+ DOut( "\nall searched (%" PRIu64 ")\n", ptree->node_searched );
+
+ if ( depth >= REJEC_MIN_DEPTH ) { sub_rejections( ptree, turn, ply ); }
+
+ if ( ! first_move_expanded )
+ {
+#if ! defined(MINIMUM)
+ if ( (int)I2From( ptree->current_move[ply-1] ) == Drop2From( pawn ) )
+ {
+ out_warning( "A checkmate by dropping pawn!!" );
+ }
+#endif
+ if ( alpha != alpha_old ) { pv_close( ptree, ply, 0 ); }
+ return alpha;
+ }
+
+
+ if ( alpha <= - ( score_mate1ply + 2 - ply ) )
+ {
+#if ! defined(MINIMUM)
+ out_warning( "A node returns a value lower than mate." );
+#endif
+ if ( alpha_old < -score_inferior && -score_inferior < beta )
+ {
+ pv_close( ptree, ply, turn ? black_superi_rep : white_superi_rep );
+ }
+ MOVE_CURR = MOVE_NA;
+ return -score_inferior;
+ }
+
+ if ( alpha != alpha_old )
+ {
+ hist_good( ptree, ptree->pv[ply].a[ply], ply, depth, turn );
+
+ pv_copy( ptree, ply );
+
+#if ! defined(MINIMUM)
+ if ( ! ( game_status & flag_learning ) )
+#endif
+ {
+ hash_store( ptree, ply, depth, turn, value_exact, alpha,
+ ptree->pv[ply].a[ply], state_node );
+ }
+ }
+ else {
+ hash_store( ptree, ply, depth, turn, value_upper, alpha, MOVE_NA,
+ state_node );
+ }
+ }
+
+ return alpha;
+}
+
+
+#if defined(TLP)
+int
+tlp_search( tree_t * restrict ptree, int alpha, int beta, int turn,
+ int depth, int ply, unsigned int state_node )
+{
+ int value, new_depth, extension, state_node_new, iret, depth_reduced;
+ int alpha_old;
+
+ assert( depth >= 3*PLY_INC );
+
+ alpha_old = alpha;
+
+ for ( ;; ) {
+ lock( & ptree->tlp_ptree_parent->tlp_lock );
+ if ( ptree->nsuc_check[ply] )
+ {
+ iret = gen_next_evasion( ptree->tlp_ptree_parent, ply, turn );
+ }
+ else { iret = gen_next_move( ptree->tlp_ptree_parent, ply, turn ); }
+ MOVE_CURR = ptree->tlp_ptree_parent->current_move[ply];
+ hist_add( ptree->tlp_ptree_parent, ply );
+ unlock( & ptree->tlp_ptree_parent->tlp_lock );
+ if ( ! iret ) { break; }
+
+ ptree->nsuc_check[ply+1] = 0U;
+ state_node_new = ( node_do_mate | node_do_recap | node_do_null
+ | node_do_futile );
+ extension = 0;
+ depth_reduced = 0;
+
+ if ( turn ? is_move_check_w( ptree, MOVE_CURR )
+ : is_move_check_b( ptree, MOVE_CURR ) )
+ {
+ ptree->check_extension_done++;
+ ptree->nsuc_check[ply+1]
+ = (unsigned char)( ptree->nsuc_check[ply-1] + 1U );
+ extension = EXT_CHECK;
+ }
+ else if ( ! ptree->nsuc_check[ply]
+ && ( state_node & node_do_recap )
+ && I2To(MOVE_CURR) == I2To(MOVE_LAST)
+ && ( MOVE_CURR == ptree->anext_move[ply].move_cap1
+ || ( ( ptree->anext_move[ply].value_cap1
+ < ptree->anext_move[ply].value_cap2 + MT_CAP_PAWN )
+ && MOVE_CURR == ptree->anext_move[ply].move_cap2 ) )
+ && ( UToCap(MOVE_LAST)
+ || ( I2IsPromote(MOVE_LAST)
+ && I2PieceMove(MOVE_LAST) != silver ) ) )
+ {
+ ptree->recap_extension_done++;
+ state_node_new = node_do_null | node_do_mate | node_do_futile;
+ if ( ! I2IsPromote(MOVE_CURR)
+ && I2PieceMove(MOVE_LAST) == UToCap(MOVE_LAST) )
+ {
+ extension = EXT_RECAP2;
+ }
+ else { extension = EXT_RECAP1; }
+ }
+
+ LimitExtension( extension, ply );
+
+ new_depth = depth + extension - PLY_INC;
+
+ /* reductions */
+ if ( ! ( state_node & node_mate_threat )
+ && ! ptree->nsuc_check[ply]
+ && ! UToCap(MOVE_CURR)
+ && ! ( I2IsPromote(MOVE_CURR) && I2PieceMove(MOVE_CURR) != silver )
+ && ptree->killers[ply].no1 != MOVE_CURR
+ && ptree->killers[ply].no2 != MOVE_CURR )
+ {
+ unsigned int key = phash( MOVE_CURR, turn );
+ unsigned int good = ptree->hist_good[key] + 1;
+ unsigned int triedx8 = ( ptree->hist_tried[key] + 2 ) * 8U;
+
+ if ( beta != alpha_old + 1 ) {
+
+ if ( good * 62U < triedx8 ) { depth_reduced = PLY_INC * 4/2; }
+ else if ( good * 46U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
+ else if ( good * 34U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
+ else if ( good * 19U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }
+
+ } else {
+
+ if ( good * 62U < triedx8 ) { depth_reduced = PLY_INC * 4/2; }
+ else if ( good * 46U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
+ else if ( good * 30U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
+ else if ( good * 12U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }
+ }
+
+ new_depth -= depth_reduced;
+ }
+
+ if ( ! ptree->nsuc_check[ply+1]
+ && ! ptree->nsuc_check[ply]
+ && new_depth < 3*PLY_INC )
+ {
+ int diff = estimate_score_diff( ptree, MOVE_CURR, turn );
+ int bound = alpha;
+
+ if ( 2*PLY_INC <= new_depth ) { bound -= EFUTIL_MG2; }
+ else if ( 1*PLY_INC <= new_depth ) { bound -= EFUTIL_MG1; }
+
+ if ( eval_max_score( ptree, MOVE_CURR, ptree->stand_pat[ply],
+ turn, diff ) <= bound )
+ {
+ continue;
+ }
+ }
+
+ MakeMove( turn, MOVE_CURR, ply );
+ if ( I2From(MOVE_CURR) < nsquare
+ && ! ptree->nsuc_check[ply]
+ && InCheck(turn) )
+ {
+ UnMakeMove( turn, MOVE_CURR, ply );
+ continue;
+ }
+
+ if ( ! ptree->nsuc_check[ply+1] && ! ptree->nsuc_check[ply] )
+ {
+ evaluate( ptree, ply+1, Flip(turn) );
+ assert( ptree->stand_pat[ply] != score_bound );
+
+ /* futility pruning */
+ if ( ( new_depth < PLY_INC && - ptree->stand_pat[ply+1] <= alpha )
+ || ( new_depth < 2*PLY_INC
+ && - ptree->stand_pat[ply+1] <= alpha - EFUTIL_MG1 )
+ || ( new_depth < 3*PLY_INC
+ && - ptree->stand_pat[ply+1] <= alpha - EFUTIL_MG2 ) )
+ {
+ UnMakeMove( turn, MOVE_CURR, ply );
+ continue;
+ }
+ }
+
+ value = -search( ptree, -alpha-1, -alpha, Flip(turn), new_depth,
+ ply + 1, state_node_new );
+ if ( ! SEARCH_ABORT && alpha < value )
+ {
+ if ( ! depth_reduced && beta != alpha+1 )
+ {
+ value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+ ply + 1, state_node_new );
+ }
+ else if ( depth_reduced )
+ {
+ new_depth += depth_reduced;
+ value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+ ply + 1, state_node_new );
+ }
+ }
+
+ UnMakeMove( turn, MOVE_CURR, ply );
+
+ if ( SEARCH_ABORT ) { return 0; }
+
+ if ( alpha < value ) {
+
+ alpha = value;
+ if ( beta <= value ) {
+ int num;
+
+ lock( &tlp_lock );
+ if ( ptree->tlp_abort )
+ {
+ unlock( &tlp_lock );
+ return 0;
+ }
+ tlp_nabort += 1;
+
+ for ( num = 0; num < tlp_max; num++ )
+ if ( ptree->tlp_ptree_parent->tlp_ptrees_sibling[num]
+ && num != ptree->tlp_id )
+ tlp_set_abort( ptree->tlp_ptree_parent->tlp_ptrees_sibling[num] );
+
+ unlock( &tlp_lock );
+
+ return value;
+ }
+ }
+ }
+
+ return alpha;
+}
+#endif /* TLP */
+
+
+static int
+detect_signals( tree_t * restrict ptree )
+{
+ unsigned int tnow, telapsed, tpondered, tsearched, tcount, tlimit, tmax;
+ unsigned int tmax_limit_count, tlimit_count, u;
+ int iret, easy_time, last_value, stable;
+
+ if ( ! ( game_status & flag_nopeek ) )
+ {
+ /* peek input-buffer to find a command */
+ iret = next_cmdline( 0 );
+ if ( iret == -1 )
+ {
+ game_status |= flag_search_error;
+ return 1;
+ }
+ else if ( iret == -2 )
+ {
+ out_warning( "%s", str_error );
+ ShutdownClient;
+ }
+ else if ( game_status & flag_quit ) { return 1; } /* EOF */
+ else if ( iret )
+ {
+ /* a command is found */
+ iret = procedure( ptree );
+ if ( iret == -1 )
+ {
+ game_status |= flag_search_error;
+ next_cmdline( 1 );
+ return 1;
+ }
+ else if ( iret == -2 )
+ {
+ out_warning( "%s", str_error );
+ next_cmdline( 1 );
+ ShutdownClient;
+ }
+ else if ( iret == 1 ) { next_cmdline( 1 ); }
+
+ if ( game_status & ( flag_quit | flag_quit_ponder
+ | flag_move_now | flag_suspend ) )
+ {
+ return 1;
+ }
+ }
+ }
+
+ /* check conditions of search-abortion, and obtain tnow and elapsed */
+ if ( node_limit <= ptree->node_searched ) { return 1; }
+
+ if ( get_elapsed( &tnow ) < 0 )
+ {
+ game_status |= flag_search_error;
+ return 1;
+ }
+
+ /* keep my connection alive */
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL
+ && SEC_KEEP_ALIVE * 1000U < tnow - time_last_send
+ && sckt_out( sckt_csa, "\n" ) < 0 )
+ {
+ game_status |= flag_search_error;
+ return 1;
+ }
+#endif
+
+#if defined(MNJ_LAN)
+ if ( sckt_mnj != SCKT_NULL && 500U < tnow - time_last_send )
+ {
+ uint64_t nodes;
+
+# if defined(TLP)
+ lock( &tlp_lock );
+ nodes = tlp_count_node( tlp_atree_work );
+ unlock( &tlp_lock );
+# else
+ nodes = ptree->node_searched;
+# endif
+
+ if ( sckt_out( sckt_mnj, "pid=%d n=%" PRIu64 "\n", mnj_posi_id,
+ nodes ) < 0 )
+ {
+ game_status |= flag_search_error;
+ return 1;
+ }
+ }
+#endif
+
+ /* shortening the time limit by depth */
+ if ( time_limit != UINT_MAX
+ && sec_limit_depth < PLY_MAX
+ && iteration_depth + 10 >= (int)sec_limit_depth )
+ {
+ if ( iteration_depth + 0 >= (int)sec_limit_depth ) { u = 1U; }
+ else if ( iteration_depth + 1 >= (int)sec_limit_depth ) { u = 3U; }
+ else if ( iteration_depth + 2 >= (int)sec_limit_depth ) { u = 7U; }
+ else if ( iteration_depth + 3 >= (int)sec_limit_depth ) { u = 15U; }
+ else if ( iteration_depth + 4 >= (int)sec_limit_depth ) { u = 31U; }
+ else if ( iteration_depth + 5 >= (int)sec_limit_depth ) { u = 63U; }
+ else if ( iteration_depth + 6 >= (int)sec_limit_depth ) { u = 127U; }
+ else if ( iteration_depth + 7 >= (int)sec_limit_depth ) { u = 255U; }
+ else if ( iteration_depth + 8 >= (int)sec_limit_depth ) { u = 511U; }
+ else if ( iteration_depth + 9 >= (int)sec_limit_depth ) { u = 1023U; }
+ else { u = 2047U; }
+
+ tlimit = u * 1000U + 1000U - time_response;
+ tmax = u * 5000U + 1000U - time_response;
+ if ( tlimit > time_limit ) { tlimit = time_limit; }
+ if ( tmax > time_max_limit ) { tmax = time_max_limit; }
+ }
+ else {
+ tlimit = time_limit;
+ tmax = time_max_limit;
+ }
+
+ telapsed = tnow - time_turn_start;
+ tpondered = time_turn_start - time_start;
+ tsearched = tnow - time_start;
+ easy_time = 0;
+ last_value = root_turn ? -last_root_value : last_root_value;
+ stable = ( tlimit != UINT_MAX
+ && ( ( root_alpha == root_value && ! root_nfail_low )
+ || last_pv.type == four_fold_rep
+ || ( root_nfail_high
+ && root_value + MT_CAP_DRAGON/8 >= last_value ) ) );
+
+ if ( tlimit != tmax )
+ {
+ tcount = tsearched;
+ tmax_limit_count = tmax;
+ tlimit_count = tlimit;
+ }
+ else {
+ tcount = telapsed;
+ tmax_limit_count = tmax + tpondered;
+ tlimit_count = tlimit + tpondered;
+ }
+
+ if ( ! ( game_status & flag_pondering )
+ && root_nmove == 1
+ && telapsed > 2000U - time_response ) { return 1; }
+
+ if ( tcount > tmax ) { return 1; }
+
+ if ( stable && tcount > tlimit ) { return 1; }
+
+ if ( stable
+ && ( tmax_limit_count * 3U < ( time_last_search - time_start ) * 5U ) )
+ {
+#if defined(DBG_EASY)
+ if ( ! easy_move )
+ {
+ Out( " The search can be terminated "
+ "before it reaches time-limit.\n" );
+ easy_move = ptree->pv[0].a[1];
+ }
+#else
+ Out( " The search is terminated before it reaches time-limit.\n" );
+ return 1;
+#endif
+ }
+
+ if ( stable
+ && easy_abs > abs( last_value )
+ && easy_min < last_value - easy_value
+ && easy_max > last_value - easy_value )
+ {
+ u = tlimit_count / 5U;
+ if ( u < tpondered ) { ; }
+ else if ( u - tpondered < 2000U - time_response )
+ {
+ u = tpondered + 2000U - time_response;
+ }
+ else {
+ u = ( ( u - tpondered ) / 1000U + 1U ) * 1000U
+ + tpondered - time_response;
+ }
+
+ if ( tsearched > u )
+ {
+ Out( " The root move %s counted as easy!!\n",
+ str_CSA_move(root_move_list[0].move) );
+#if defined(DBG_EASY)
+ easy_move = ptree->pv[0].a[1];
+ easy_abs = 0;
+#else
+ return 1;
+#endif
+ }
+ else if ( tsearched + 500U > u ) { easy_time = 1; }
+ }
+
+ /* renew node_per_second */
+ {
+ double dn, dd;
+
+ dn = (double)node_last_check * 1000.0;
+ dd = (double)( tnow - time_last_check ) + 0.1;
+ u = (unsigned int)( dn / dd );
+ if ( node_per_second > u * 2U ) { node_per_second /= 2U; }
+ else if ( node_per_second < u / 2U ) { node_per_second *= 2U; }
+ else { node_per_second = u; }
+ }
+
+ /* renew node_next_signal */
+ if ( ! ( game_status & flag_pondering ) && root_nmove == 1 )
+ {
+ u = 2000U - time_response;
+ }
+ else { u = tlimit; }
+
+ if ( ! ( game_status & ( flag_pondering | flag_puzzling ) )
+ && ! easy_time
+ && u > tcount + 500U )
+ {
+ node_next_signal = node_per_second / 4U;
+ }
+ else { node_next_signal = node_per_second / 32U; }
+
+ /* renew time_last_check and node_last_check */
+ time_last_check = tnow;
+ node_last_check = 0;
+
+
+ return 0;
+}
+
+
+int
+is_move_check_b( const tree_t * restrict ptree, unsigned int move )
+{
+ const int from = (int)I2From(move);
+ const int to = (int)I2To(move);
+ int is_check, ipiece_move, idirec;
+ bitboard_t bb;
+
+ is_check = 0;
+
+ if ( from >= nsquare ) { ipiece_move = From2Drop(from); }
+ else {
+ ipiece_move = (int)I2PieceMove(move);
+ if ( I2IsPromote(move) ) { ipiece_move += promote; }
+
+ idirec = (int)adirec[SQ_WKING][from];
+ if ( idirec && idirec != (int)adirec[SQ_WKING][to]
+ && is_pinned_on_white_king( ptree, from, idirec ) )
+ {
+ is_check = 1;
+ goto end;
+ }
+ }
+
+ switch ( ipiece_move )
+ {
+ case pawn:
+ if ( BOARD[to-nfile] == -king ) { is_check = 1; }
+ break;
+
+ case lance:
+ AttackBLance( bb, to );
+ if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+ break;
+
+ case knight:
+ if ( BBContract(abb_b_knight_attacks[to],BB_WKING) ) { is_check = 1; }
+ break;
+
+ case silver:
+ if ( BBContract(abb_b_silver_attacks[to],BB_WKING) ) { is_check = 1; }
+ break;
+
+ case gold: case pro_pawn:
+ case pro_lance: case pro_knight:
+ case pro_silver:
+ if ( BBContract(abb_b_gold_attacks[to],BB_WKING) ) { is_check = 1; }
+ break;
+
+ case bishop:
+ AttackBishop( bb, to );
+ if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+ break;
+
+ case rook:
+ AttackRook( bb, to );
+ if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+ break;
+
+ case king:
+ break;
+
+ case horse:
+ AttackHorse( bb, to );
+ if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+ break;
+
+ default:
+ assert( ipiece_move == dragon );
+ AttackDragon( bb, to );
+ if ( BBContract( bb, BB_WKING ) ) { is_check = 1; }
+ break;
+ }
+
+ end:
+ return is_check;
+}
+
+
+int
+is_move_check_w( const tree_t * restrict ptree, unsigned int move )
+{
+ const int from = (int)I2From(move);
+ const int to = (int)I2To(move);
+ int is_check, ipiece_move, idirec;
+ bitboard_t bb;
+
+ is_check = 0;
+
+ if ( from >= nsquare ) { ipiece_move = From2Drop(from); }
+ else {
+ ipiece_move = (int)I2PieceMove(move);
+ if ( I2IsPromote(move) ) { ipiece_move += promote; }
+
+ idirec = (int)adirec[SQ_BKING][from];
+ if ( idirec && idirec != (int)adirec[SQ_BKING][to]
+ && is_pinned_on_black_king( ptree, from, idirec ) )
+ {
+ is_check = 1;
+ goto end;
+ }
+ }
+
+ switch ( ipiece_move )
+ {
+ case pawn:
+ if ( BOARD[to+nfile] == king ) { is_check = 1; }
+ break;
+
+ case lance:
+ AttackWLance( bb, to );
+ if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+ break;
+
+ case knight:
+ if ( BBContract(abb_w_knight_attacks[to],BB_BKING) ) { is_check = 1; }
+ break;
+
+ case silver:
+ if ( BBContract(abb_w_silver_attacks[to],BB_BKING) ) { is_check = 1; }
+ break;
+
+ case gold: case pro_pawn:
+ case pro_lance: case pro_knight:
+ case pro_silver:
+ if ( BBContract(abb_w_gold_attacks[to],BB_BKING) ) { is_check = 1; }
+ break;
+
+ case bishop:
+ AttackBishop( bb, to );
+ if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+ break;
+
+ case rook:
+ AttackRook( bb, to );
+ if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+ break;
+
+ case king:
+ break;
+
+ case horse:
+ AttackHorse( bb, to );
+ if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+ break;
+
+ default:
+ assert( ipiece_move == dragon );
+ AttackDragon( bb, to );
+ if ( BBContract( bb, BB_BKING ) ) { is_check = 1; }
+ break;
+ }
+
+ end:
+ return is_check;
+}
+
+
+void
+pv_close( tree_t * restrict ptree, int ply, int type )
+{
+ ptree->pv[ply-1].a[ply-1] = (ptree)->current_move[ply-1];
+ ptree->pv[ply-1].length = (unsigned char)(ply-1);
+ ptree->pv[ply-1].type = (unsigned char)type;
+ ptree->pv[ply-1].depth = (unsigned char)iteration_depth;
+}
+
+
+void
+pv_copy( tree_t * restrict ptree, int ply )
+{
+ memcpy( &(ptree->pv[ply-1].a[ply]), &(ptree->pv[ply].a[ply]),
+ ( ptree->pv[ply].length-ply+1 ) * sizeof(unsigned int) );
+ ptree->pv[ply-1].type = ptree->pv[ply].type;
+ ptree->pv[ply-1].length = ptree->pv[ply].length;
+ ptree->pv[ply-1].depth = ptree->pv[ply].depth;
+ ptree->pv[ply-1].a[ply-1] = ptree->current_move[ply-1];
+}
+
+
+static int
+detect_rep( tree_t * restrict ptree, int ply, int turn )
+{
+ if ( ply < 4 ) { return detect_repetition( ptree, ply, turn, 2 ); }
+ else {
+ int n, i, imin, iret;
+
+ n = root_nrep + ply - 1;
+ imin = n - REP_MAX_PLY;
+ if ( imin < 0 ) { imin = 0; }
+
+ for ( i = n-2; i >= imin; i-- )
+ if ( ptree->rep_board_list[i] == HASH_KEY )
+ {
+ iret = rep_type( ptree, n, i, ply, turn );
+ if ( iret ) { return iret; }
+ }
+ }
+
+ return no_rep;
+}
+
+
+static int
+rep_type( const tree_t * restrict ptree, int n, int i, int ply, int turn )
+{
+ const unsigned int hand1 = HAND_B;
+ const unsigned int hand2 = ptree->rep_hand_list[i];
+
+ if ( (n-i) & 1 )
+ {
+ if ( turn )
+ {
+ if ( is_hand_eq_supe( hand2, hand1 ) ) { return white_superi_rep; }
+ }
+ else if ( is_hand_eq_supe( hand1, hand2 ) ) { return black_superi_rep; }
+ }
+ else if ( hand1 == hand2 )
+ {
+ const int ncheck = (int)ptree->nsuc_check[ply];
+ const int nchecked = (int)ptree->nsuc_check[ply-1];
+
+ if ( ncheck * 2 - 2 >= n-i ) { return perpetual_check; }
+ else if ( nchecked * 2 >= n-i ) { return perpetual_check2; }
+ else { return four_fold_rep; }
+ }
+ else if ( is_hand_eq_supe( hand1, hand2 ) ) { return black_superi_rep; }
+ else if ( is_hand_eq_supe( hand2, hand1 ) ) { return white_superi_rep; }
+
+ return no_rep;
+}
+
+
+static void
+hist_add( tree_t * restrict ptree, int ply )
+{
+ if ( ptree->nsuc_check[ply] ) { return; }
+ if ( UToCap(MOVE_CURR) ) { return; }
+ if ( I2IsPromote(MOVE_CURR)
+ && I2PieceMove(MOVE_CURR) != silver ) { return; }
+
+ assert( ptree->hist_nmove[ply] < MAX_LEGAL_MOVES );
+ ptree->hist_move[ply][ ptree->hist_nmove[ply]++ ] = MOVE_CURR;
+}
+
+
+static void
+hist_good( tree_t * restrict ptree, unsigned int move_good, int ply,
+ int depth, int turn )
+{
+ unsigned int key, move;
+ int i, n, value, value_no1, value_no2;
+
+ if ( ptree->nsuc_check[ply] ) { return; }
+
+ value = p_value_ex[15+UToCap(move_good)];
+ value_no1 = p_value_ex[15+BOARD[I2To(ptree->amove_killer[ply].no1)]];
+ value_no2 = p_value_ex[15+BOARD[I2To(ptree->amove_killer[ply].no2)]];
+ if ( move_good == ptree->anext_move[ply].move_cap1 )
+ {
+ if ( ( ptree->anext_move[ply].phase_done & phase_killer1 )
+ && UToFromToPromo(move_good) != ptree->amove_killer[ply].no1 )
+ {
+ ptree->amove_killer[ply].no1_value
+ = ptree->anext_move[ply].value_cap1 - value - 1;
+ }
+ if ( ( ptree->anext_move[ply].phase_done & phase_killer2 )
+ && UToFromToPromo(move_good) != ptree->amove_killer[ply].no2 )
+ {
+ ptree->amove_killer[ply].no2_value
+ = ptree->anext_move[ply].value_cap1 - value - 2;
+ }
+ }
+ else if ( UToFromToPromo(move_good) == ptree->amove_killer[ply].no1 )
+ {
+ if ( ( ptree->anext_move[ply].phase_done & phase_cap1 )
+ && ( ptree->amove_killer[ply].no1_value + value
+ < ptree->anext_move[ply].value_cap1 + 1 ) )
+ {
+ ptree->amove_killer[ply].no1_value
+ = ptree->anext_move[ply].value_cap1 - value + 1;
+ }
+ if ( ( ptree->anext_move[ply].phase_done & phase_killer2 )
+ && ( ptree->amove_killer[ply].no1_value + value
+ < ptree->amove_killer[ply].no2_value + value_no2 + 1 ) )
+ {
+ ptree->amove_killer[ply].no1_value
+ = ptree->amove_killer[ply].no2_value + value_no2 - value + 1;
+ }
+ }
+ else if ( UToFromToPromo(move_good) == ptree->amove_killer[ply].no2 )
+ {
+ unsigned int uswap;
+ int iswap;
+
+ if ( ( ptree->anext_move[ply].phase_done & phase_cap1 )
+ && ( ptree->amove_killer[ply].no2_value + value
+ < ptree->anext_move[ply].value_cap1 + 1 ) )
+ {
+ ptree->amove_killer[ply].no2_value
+ = ptree->anext_move[ply].value_cap1 - value + 1;
+ }
+ if ( ( ptree->anext_move[ply].phase_done & phase_killer1 )
+ && ( ptree->amove_killer[ply].no2_value + value
+ < ptree->amove_killer[ply].no1_value + value_no1 + 1 ) )
+ {
+ ptree->amove_killer[ply].no2_value
+ = ptree->amove_killer[ply].no1_value + value_no1 - value + 1;
+ }
+
+ uswap = ptree->amove_killer[ply].no1;
+ ptree->amove_killer[ply].no1 = ptree->amove_killer[ply].no2;
+ ptree->amove_killer[ply].no2 = uswap;
+
+ iswap = ptree->amove_killer[ply].no1_value;
+ ptree->amove_killer[ply].no1_value = ptree->amove_killer[ply].no2_value;
+ ptree->amove_killer[ply].no2_value = iswap;
+ }
+ else {
+ ptree->amove_killer[ply].no2 = ptree->amove_killer[ply].no1;
+ ptree->amove_killer[ply].no1 = UToFromToPromo(move_good);
+
+ if ( ptree->anext_move[ply].phase_done & phase_killer1 )
+ {
+ i = swap( ptree, move_good, -MT_CAP_ROOK, MT_CAP_ROOK, turn );
+ i -= value + 1;
+
+ if ( ptree->amove_killer[ply].no1_value > i )
+ {
+ ptree->amove_killer[ply].no1_value = i;
+ }
+ }
+ ptree->amove_killer[ply].no2_value = ptree->amove_killer[ply].no1_value;
+ ptree->amove_killer[ply].no1_value
+ = ptree->anext_move[ply].value_cap1 - value + 1;
+ }
+
+
+ if ( UToCap(move_good) ) { return; }
+ if ( I2IsPromote(move_good)
+ && I2PieceMove(move_good) != silver ) { return; }
+
+ if ( ptree->killers[ply].no1 != move_good )
+ {
+ ptree->killers[ply].no2 = ptree->killers[ply].no1;
+ ptree->killers[ply].no1 = move_good;
+ }
+
+ if ( depth < 1 ) { depth = 1; }
+
+ n = ptree->hist_nmove[ply];
+ for ( i = 0; i < n; i++ )
+ {
+ move = ptree->hist_move[ply][i];
+ assert( is_move_valid( ptree, move, turn ) );
+
+ key = phash( move, turn );
+ if ( ptree->hist_tried[key] >= HIST_MAX )
+ {
+ ptree->hist_good[key] /= 2U;
+ ptree->hist_tried[key] /= 2U;
+ }
+
+ assert( ptree->hist_tried[key] < HIST_MAX );
+ ptree->hist_tried[key]
+ = (unsigned short)( (int)ptree->hist_tried[key] + depth );
+ }
+
+ assert( is_move_valid( ptree, move_good, turn ) );
+ key = phash( move_good, turn );
+
+ assert( ptree->hist_good[key] < HIST_MAX );
+ ptree->hist_good[key]
+ = (unsigned short)( (int)ptree->hist_good[key] + depth );
+}
--- /dev/null
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "shogi.h"
+
+static int find_root_move( unsigned int move );
+static int save_result( tree_t * restrict ptree, int value, int beta,
+ int turn );
+
+#if defined(MPV)
+static int mpv_set_bound( int alpha );
+static int mpv_find_min( int *pnum );
+static int mpv_add_result( tree_t * restrict ptree, int value );
+static void mpv_sub_result( unsigned int move );
+static void mpv_out( tree_t * restrict ptree, int turn, unsigned int time );
+#endif
+
+#if defined(NO_STDOUT) && defined(NO_LOGGING)
+# define NextRootMove(a,b) next_root_move(a)
+static int next_root_move( tree_t * restrict ptree );
+#else
+# define NextRootMove(a,b) next_root_move(a,b)
+static int next_root_move( tree_t * restrict ptree, int turn );
+#endif
+
+int
+searchr( tree_t * restrict ptree, int alpha, int beta, int turn, int depth )
+{
+ uint64_t root_nodes_start;
+ int value, first_move_expanded, i;
+ int new_depth, extension, ply, state_node_new;
+#if defined(MPV)
+ int bound = INT_MIN;
+#endif
+
+ first_move_expanded = 1;
+ ply = 1;
+ ptree->move_last[1] = ptree->move_last[0];
+
+ while( NextRootMove( ptree, turn ) )
+ {
+ root_nodes_start = ptree->node_searched;
+ MakeMove( turn, MOVE_CURR, 1 );
+
+ assert( ! InCheck( turn ) );
+
+ state_node_new = ( node_do_mate | node_do_null | node_do_futile
+ | node_do_recap );
+ if ( InCheck(Flip(turn)) )
+ {
+ ptree->check_extension_done++;
+ ptree->nsuc_check[2] = (unsigned char)( ptree->nsuc_check[0] + 1U );
+ extension = EXT_CHECK - PLY_INC;
+ }
+ else {
+ extension = - PLY_INC;
+ ptree->nsuc_check[2] = 0;
+ }
+
+ if ( first_move_expanded )
+ {
+#if defined(MPV)
+ if ( root_mpv ) { bound = alpha; }
+#endif
+ new_depth = depth + extension;
+ value = -search( ptree, -beta, -alpha, Flip(turn), new_depth, 2,
+ state_node_new );
+ if ( root_abort )
+ {
+ UnMakeMove( turn, MOVE_CURR, 1 );
+ return 0;
+ }
+
+ if ( value <= alpha )
+ {
+ UnMakeMove( turn, MOVE_CURR, 1 );
+ return value;
+ }
+
+ first_move_expanded = 0;
+ }
+#if defined(MPV)
+ else if ( root_mpv )
+ {
+ bound = mpv_set_bound( alpha );
+ if ( depth + extension >= PLY_INC || ptree->nsuc_check[2] )
+ {
+ new_depth = depth + extension;
+
+ value = -search( ptree, -bound-1, -bound, Flip(turn), new_depth,
+ 2, state_node_new );
+ if ( ! root_abort && bound < value )
+ {
+ new_depth = depth + extension;
+ value = -search( ptree, -beta, -bound, Flip(turn), new_depth,
+ 2, state_node_new );
+ }
+ if ( root_abort )
+ {
+ UnMakeMove( turn, MOVE_CURR, 1 );
+ return 0;
+ }
+ }
+ else {
+ value = -search_quies( ptree, -beta, -bound, Flip(turn), 2, 1 );
+ }
+ }
+#endif /* MPV */
+ else {
+ new_depth = depth + extension;
+
+ value = -search( ptree, -alpha-1, -alpha, Flip(turn), new_depth, 2,
+ state_node_new );
+ if ( root_abort )
+ {
+ UnMakeMove( turn, MOVE_CURR, 1 );
+ return 0;
+ }
+ if ( alpha < value )
+ {
+ MnjOut( "pid=%d move=%s v=%dl n=% " PRIu64 " \n",
+ mnj_posi_id, str_CSA_move(MOVE_CURR), alpha+1,
+ ptree->node_searched );
+
+ new_depth = depth + extension;
+ easy_abs = 0;
+ value = -search( ptree, -beta, -alpha, Flip(turn), new_depth,
+ 2, state_node_new );
+ if ( root_abort )
+ {
+ const char *str;
+ double dvalue;
+ char ch;
+
+ UnMakeMove( turn, MOVE_CURR, 1 );
+ pv_close( ptree, 2, pv_fail_high );
+ time_last_result = time_last_check;
+ time_last_eff_search = time_last_search;
+ root_value = alpha+1;
+ ptree->pv[0] = ptree->pv[1];
+ if ( turn )
+ {
+ dvalue = -(double)alpha;
+ ch = '-';
+ }
+ else {
+ dvalue = alpha;
+ ch = '+';
+ }
+ str = str_CSA_move_plus( ptree, MOVE_CURR, 1, turn );
+ Out( " %7.2f 1.%c%s [%c0!]\n",
+ dvalue / 100.0, ch, str, ch );
+ if ( game_status & flag_pondering )
+ {
+ OutCsaShogi( "info%+.2f %c%s %c%s [%c0!]\n",
+ dvalue / 100.0, ach_turn[Flip(turn)],
+ str_CSA_move(ponder_move),
+ ch, str, ch );
+ }
+ else {
+ OutCsaShogi( "info%+.2f %c%s [%c0!]\n",
+ dvalue / 100.0, ch, str, ch );
+ }
+ return 0;
+ }
+ }
+ }
+
+ UnMakeMove( turn, MOVE_CURR, 1 );
+
+ i = find_root_move( MOVE_CURR );
+ root_move_list[i].nodes = ptree->node_searched - root_nodes_start;
+
+#if defined(MPV)
+ if ( root_mpv && value < beta )
+ {
+ mpv_sub_result( MOVE_CURR );
+ if ( bound < value && mpv_add_result( ptree, value ) < 0 )
+ {
+ game_status |= flag_search_error;
+ return 1;
+ }
+ }
+#endif
+
+ if ( alpha < value )
+ {
+ if ( save_result( ptree, value, beta, turn ) < 0 )
+ {
+ game_status |= flag_search_error;
+ return 1;
+ }
+ if ( beta <= value )
+ {
+ hash_store( ptree, 1, depth, turn, value_lower, value,
+ MOVE_CURR, 0 );
+ return value;
+ }
+ alpha = value;
+ }
+ }
+ if ( root_abort ) { return 0; }
+
+#if ! defined(MINIMUM)
+ if ( ! ( game_status & flag_learning ) )
+#endif
+ {
+ hash_store( ptree, 1, depth, turn, value_exact, alpha,
+ ptree->pv[1].a[1], 0 );
+ }
+
+ return alpha;
+}
+
+
+void
+out_pv( tree_t * restrict ptree, int value, int turn, unsigned int time )
+{
+ const char *str;
+ double dvalue;
+ int ply, tt, is_out;
+
+ tt = turn;
+ is_out = ( iteration_depth > 3 || abs(value) > score_max_eval ) ? 1 : 0;
+
+#if defined(MPV)
+ if ( root_mpv ) { is_out = 0; }
+#endif
+
+ if ( is_out )
+ {
+ str = str_time_symple( time );
+ dvalue = (double)( turn ? -value : value ) / 100.0;
+ OutCsaShogi( "info%+.2f", dvalue );
+ if ( game_status & flag_pondering )
+ {
+ OutCsaShogi( " %c%s", ach_turn[Flip(turn)],
+ str_CSA_move(ponder_move) );
+ }
+
+ if ( ptree->pv[0].length )
+ {
+ int i = find_root_move( ptree->pv[0].a[1] );
+ if ( root_move_list[i].status & flag_first )
+ {
+ Out( " %2d %6s %7.2f ", iteration_depth, str, dvalue );
+ }
+ else { Out( " %6s %7.2f ", str, dvalue ); }
+ }
+ }
+
+ for ( ply = 1; ply <= ptree->pv[0].length; ply++ )
+ {
+ if ( is_out )
+ {
+ if ( ply > 1 && ! ( (ply-1) % 4 ) )
+ {
+ Out( "\n " );
+ }
+ str = str_CSA_move_plus( ptree, ptree->pv[0].a[ply], ply, tt );
+ OutCsaShogi( " %c%s", ach_turn[tt], str );
+ Out( "%2d.%c%-11s", ply, ach_turn[tt], str );
+ }
+
+ MakeMove( tt, ptree->pv[0].a[ply], ply );
+ tt = Flip(tt);
+ value = -value;
+ }
+
+ if ( ptree->pv[0].type == hash_hit )
+ {
+ int i, value_type;
+
+ for ( ; ply < PLY_MAX; ply++ )
+ {
+ ptree->amove_hash[ply] = 0;
+ value_type = hash_probe( ptree, ply, 0, tt, -score_bound,
+ score_bound, 0 );
+ if ( ! ( value_type == value_exact
+ && value == HASH_VALUE
+ && is_move_valid( ptree, ptree->amove_hash[ply], tt ) ) )
+ {
+ break;
+ }
+ ptree->pv[0].a[ply] = ptree->amove_hash[ply];
+ for ( i = 1; i < ply; i++ )
+ if ( ptree->pv[0].a[i] == ptree->pv[0].a[ply] ) { goto rep_esc; }
+
+ if ( is_out )
+ {
+ if ( ply > 1 && ! ( (ply-1) % 4 ) )
+ {
+ Out( "\n " );
+ }
+ str = str_CSA_move_plus( ptree, ptree->pv[0].a[ply], ply,
+ tt );
+ OutCsaShogi( " %c%s", ach_turn[tt], str );
+ Out( "%2d:%c%-11s", ply, ach_turn[tt], str );
+ }
+
+ MakeMove( tt, ptree->pv[0].a[ply], ply );
+ if ( InCheck(tt) )
+ {
+ UnMakeMove( tt, ptree->amove_hash[ply], ply );
+ break;
+ }
+ ptree->pv[0].length++;
+ tt = Flip(tt);
+ value = -value;
+ }
+ }
+ rep_esc:
+
+ if ( is_out && ptree->pv[0].type != no_rep )
+ {
+ if ( (((ply-1) % 4) == 0) && (ply != 1) )
+ {
+ Out( "\n " );
+ }
+ str = NULL;
+ switch ( ptree->pv[0].type )
+ {
+ case perpetual_check: str = "PER. CHECK"; break;
+ case four_fold_rep: str = "REPETITION"; break;
+ case black_superi_rep:
+ case white_superi_rep: str = "SUPERI. POSI."; break;
+ case prev_solution: str = "PREV. SEARCH"; break;
+ case hash_hit: str = "HASH HIT"; break;
+ case book_hit: str = "BOOK HIT"; break;
+ case pv_fail_high: str = "FAIL HIGH"; break;
+ case mate_search: str = "MATE SEARCH"; break;
+ }
+ if ( str != NULL ) { Out( " <%s>", str ); }
+ }
+ for ( ply--; ply >= 1; ply-- )
+ {
+ tt = Flip(tt);
+ UnMakeMove( tt, ptree->pv[0].a[ply], ply );
+ }
+
+ if ( is_out )
+ {
+ OutCsaShogi( "\n" );
+ Out( "\n" );
+ }
+}
+
+
+static int
+save_result( tree_t * restrict ptree, int value, int beta, int turn )
+{
+ root_move_t root_move_temp;
+ int i;
+
+ if ( get_elapsed( &time_last_result ) < 0 ) { return -1; }
+
+ i = find_root_move( ptree->current_move[1] );
+ if ( i )
+ {
+ root_move_temp = root_move_list[i];
+ for ( ; i > 0; i-- ) { root_move_list[i] = root_move_list[i-1]; }
+ root_move_list[0] = root_move_temp;
+ }
+
+ if ( beta <= value ) { pv_close( ptree, 2, pv_fail_high ); }
+
+ if ( ptree->pv[0].a[1] != ptree->pv[1].a[1] )
+ {
+ time_last_eff_search = time_last_search;
+ }
+
+ ptree->pv[0] = ptree->pv[1];
+ root_value = value;
+
+ if ( value < beta )
+ {
+ MnjOut( "pid=%d move=%s v=%de n=%" PRIu64 "\n", mnj_posi_id,
+ str_CSA_move(ptree->pv[1].a[1]), value, ptree->node_searched );
+ out_pv( ptree, value, turn, time_last_result - time_start );
+ }
+
+ return 1;
+}
+
+
+static int
+#if defined(NO_STDOUT) && defined(NO_LOGGING)
+next_root_move( tree_t * restrict ptree )
+#else
+next_root_move( tree_t * restrict ptree, int turn )
+#endif
+{
+ int i, n;
+
+ n = root_nmove;
+ for ( i = 0; i < n; i++ )
+ {
+ if ( root_move_list[i].status & flag_searched ) { continue; }
+ root_move_list[i].status |= flag_searched;
+ ptree->current_move[1] = root_move_list[i].move;
+
+#if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
+ if ( iteration_depth > 5 )
+ {
+ const char *str_move;
+ char str[9];
+ /* check: does this code have small impact on performance? */
+ str_move = str_CSA_move_plus( ptree, ptree->current_move[1], 1,
+ turn);
+ snprintf( str, 9, "%d/%d", i+1, root_nmove );
+ if ( root_move_list[i].status & flag_first )
+ {
+ Out( "(%2d) %7s* 1.%c%s \r",
+ iteration_depth, str, ach_turn[turn], str_move );
+ }
+ else {
+ Out( " %7s* 1.%c%s \r",
+ str, ach_turn[turn], str_move );
+ }
+ }
+#endif
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+find_root_move( unsigned int move )
+{
+ int i, n;
+
+ n = root_nmove;
+ for ( i = 0; i < n; i++ )
+ if ( root_move_list[i].move == move ) { break; }
+
+ return i;
+}
+
+
+#if defined(MPV)
+static void
+mpv_out( tree_t * restrict ptree, int turn, unsigned int time )
+{
+ int mpv_out, ipv, best;
+
+ best = (int)mpv_pv[0].a[0] - 32768;
+ mpv_out = ( iteration_depth > 3 || abs(best) > score_max_eval ) ? 1 : 0;
+
+ for ( ipv = 0; mpv_pv[ipv].length; ipv++ )
+ {
+ const char *str;
+ double dvalue;
+ int tt, is_out, value, ply;
+
+ assert( ipv < mpv_num*2 );
+ tt = turn;
+ value = (int)mpv_pv[ipv].a[0] - 32768;
+ if ( mpv_out && value > best - mpv_width && ipv < mpv_num )
+ {
+ is_out = 1;
+ }
+ else { is_out = 0; }
+
+ if ( is_out )
+ {
+ dvalue = (double)( turn ? -value : value ) / 100.0;
+ if ( is_out && ! ipv ) { OutCsaShogi( "info" ); }
+ if ( is_out && ipv ) { OutCsaShogi( ":" ); }
+
+ OutCsaShogi( "%+.2f", dvalue );
+ if ( game_status & flag_pondering )
+ {
+ OutCsaShogi( " %c%s", ach_turn[Flip(turn)],
+ str_CSA_move(ponder_move) );
+ }
+
+ str = str_time_symple( time );
+ ply = mpv_pv[ipv].depth;
+ if ( ! ipv ) { Out( "o%2d %6s %7.2f ", ply, str, dvalue ); }
+ else { Out( " %2d %7.2f ", ply, dvalue ); }
+ }
+
+ for ( ply = 1; ply <= mpv_pv[ipv].length; ply++ )
+ {
+ if ( is_out )
+ {
+ if ( ply > 1 && ! ( (ply-1) % 4 ) )
+ {
+ Out( "\n " );
+ }
+ str = str_CSA_move_plus( ptree, mpv_pv[ipv].a[ply], ply, tt );
+ OutCsaShogi( " %c%s", ach_turn[tt], str );
+ Out( "%2d.%c%-11s", ply, ach_turn[tt], str );
+ }
+
+ assert( is_move_valid( ptree, mpv_pv[ipv].a[ply], tt ) );
+ MakeMove( tt, mpv_pv[ipv].a[ply], ply );
+ tt = Flip(tt);
+ value = -value;
+ }
+
+ if ( mpv_pv[ipv].type == hash_hit )
+ {
+ int i, value_type;
+
+ for ( ; ply < PLY_MAX; ply++ )
+ {
+ ptree->amove_hash[ply] = 0;
+ value_type = hash_probe( ptree, ply, 0, tt, -score_bound,
+ score_bound, 0 );
+ if ( ! ( value_type == value_exact
+ && value == HASH_VALUE
+ && is_move_valid(ptree,ptree->amove_hash[ply],tt) ) )
+ {
+ break;
+ }
+ mpv_pv[ipv].a[ply] = ptree->amove_hash[ply];
+ for ( i = 1; i < ply; i++ )
+ if ( mpv_pv[ipv].a[i]
+ == mpv_pv[ipv].a[ply] ) { goto rep_esc; }
+
+ if ( is_out )
+ {
+ if ( ply > 1 && ! ( (ply-1) % 4 ) )
+ {
+ Out( "\n " );
+ }
+ str = str_CSA_move_plus( ptree, mpv_pv[ipv].a[ply], ply,
+ tt );
+ OutCsaShogi( " %c%s", ach_turn[tt], str );
+ Out( "%2d:%c%-11s", ply, ach_turn[tt], str );
+ }
+
+ MakeMove( tt, mpv_pv[ipv].a[ply], ply );
+ if ( InCheck(tt) )
+ {
+ UnMakeMove( tt, ptree->amove_hash[ply], ply );
+ break;
+ }
+ mpv_pv[ipv].length++;
+ tt = Flip(tt);
+ value = -value;
+ }
+ }
+ rep_esc:
+
+ if ( is_out && mpv_pv[ipv].type != no_rep )
+ {
+ if ( (((ply-1) % 4) == 0) && (ply != 1) )
+ {
+ Out( "\n " );
+ }
+ str = NULL;
+ switch ( mpv_pv[ipv].type )
+ {
+ case perpetual_check: str = "PER. CHECK"; break;
+ case four_fold_rep: str = "REPETITION"; break;
+ case black_superi_rep:
+ case white_superi_rep: str = "SUPERI. POSI."; break;
+ case prev_solution: str = "PREV. SEARCH"; break;
+ case hash_hit: str = "HASH HIT"; break;
+ case book_hit: str = "BOOK HIT"; break;
+ case pv_fail_high: str = "FAIL HIGH"; break;
+ case mate_search: str = "MATE SEARCH"; break;
+ }
+ if ( str != NULL ) { Out( " <%s>", str ); }
+ }
+ for ( ply--; ply >= 1; ply-- )
+ {
+ tt = Flip(tt);
+ UnMakeMove( tt, mpv_pv[ipv].a[ply], ply );
+ }
+
+ if ( is_out ) { Out( "\n" ); }
+ }
+
+ if ( mpv_out ) { OutCsaShogi( "\n" ); }
+}
+
+
+static void
+mpv_sub_result( unsigned int move )
+{
+ int i;
+
+ for ( i = 0; mpv_pv[i].length; i++ )
+ {
+ assert( i < mpv_num*2 );
+ assert( i < root_nmove*2 );
+ assert( mpv_pv[i].depth <= iteration_depth );
+ assert( -score_bound < (int)mpv_pv[i].a[0]-32768 );
+ assert( (int)mpv_pv[i].a[0]-32768 < score_bound );
+
+ if ( mpv_pv[i].a[1] == move ) { break; }
+ }
+
+ for ( ; mpv_pv[i].length; i++ )
+ {
+ assert( i < mpv_num*2 );
+ assert( i < root_nmove*2 );
+ assert( mpv_pv[i].depth <= iteration_depth );
+ assert( -score_bound < (int)mpv_pv[i].a[0]-32768 );
+ assert( (int)mpv_pv[i].a[0]-32768 < score_bound );
+
+ mpv_pv[i] = mpv_pv[i+1];
+ }
+}
+
+
+static int
+mpv_add_result( tree_t * restrict ptree, int value )
+{
+ pv_t pv_tmp, pv;
+ unsigned int time;
+ int i, vmin, num;
+
+ vmin = mpv_find_min( &num );
+ assert( num <= mpv_num );
+ assert( num < root_nmove );
+ assert( -score_bound < value );
+ assert( value < score_bound );
+
+ /* remove the weakest pv if all of slots are full */
+ if ( num == mpv_num )
+ {
+ for ( i = 0; mpv_pv[i].length; i++ )
+ {
+ assert( i < mpv_num*2 );
+ assert( i < root_nmove*2 );
+ assert( mpv_pv[i].depth <= iteration_depth );
+ assert( -score_bound < (int)mpv_pv[i].a[0]-32768 );
+ assert( (int)mpv_pv[i].a[0]-32768 < score_bound );
+
+ if ( mpv_pv[i].depth == iteration_depth
+ && mpv_pv[i].a[0] == (unsigned int)(vmin+32768) ) { break; }
+ }
+ assert( i != mpv_num*2 );
+ assert( mpv_pv[i].length );
+ do {
+ assert( i < mpv_num*2 );
+ assert( i < root_nmove*2 );
+ mpv_pv[i] = mpv_pv[i+1];
+ i++;
+ } while ( mpv_pv[i].length );
+ }
+
+ /* add a pv */
+ for ( i = 0; mpv_pv[i].length; i++ )
+ {
+ assert( i < mpv_num*2 );
+ assert( i < root_nmove*2 );
+ assert( -score_bound < (int)mpv_pv[i].a[0]-32768 );
+ assert( (int)mpv_pv[i].a[0]-32768 < score_bound );
+
+ if ( mpv_pv[i].a[0] < (unsigned int)(value+32768) ) { break; }
+ }
+
+ pv = ptree->pv[1];
+ pv.a[0] = (unsigned int)(value+32768);
+ do {
+ assert( i < mpv_num*2 );
+ assert( i < root_nmove*2 );
+ pv_tmp = mpv_pv[i];
+ mpv_pv[i] = pv;
+ pv = pv_tmp;
+ i += 1;
+ } while ( pv.length );
+
+ if ( get_elapsed( &time ) < 0 ) { return -1; }
+
+ mpv_out( ptree, root_turn, time - time_start );
+
+ return 1;
+}
+
+
+static int
+mpv_set_bound( int alpha )
+{
+ int bound, num, value;
+
+ bound = alpha - mpv_width;
+ if ( bound < -score_bound ) { bound = -score_bound; }
+
+ value = mpv_find_min( &num );
+ assert( num <= mpv_num );
+ assert( num < root_nmove );
+ assert( num );
+ assert( -score_bound < value );
+ assert( value < score_bound );
+ if ( num == mpv_num && bound < value ) { bound = value; }
+
+ return bound;
+}
+
+
+static int
+mpv_find_min( int *pnum )
+{
+ int i, num;
+ unsigned int a[ MPV_MAX_PV+1 ], u, utemp;
+
+ a[0] = 0;
+ num = 0;
+ for ( i = 0; mpv_pv[i].length; i++ )
+ {
+ assert( i < mpv_num*2 );
+ assert( i < root_nmove*2 );
+ assert( mpv_pv[i].depth <= iteration_depth );
+
+ if ( mpv_pv[i].depth == iteration_depth )
+ {
+ u = mpv_pv[i].a[0];
+ assert( -score_bound < (int)u-32768 );
+ assert( (int)u-32768 < score_bound );
+
+ for ( num = 0; u <= a[num]; num++ );
+ do {
+ assert( num < mpv_num );
+ assert( num < root_nmove );
+ utemp = a[num];
+ a[num] = u;
+ u = utemp;
+ num += 1;
+ } while ( u );
+ a[num] = 0;
+ }
+ }
+
+ if ( pnum ) { *pnum = num; }
+
+ if ( num ) { return (int)a[num-1] - 32768; }
+
+ return 0;
+}
+#endif
--- /dev/null
+#ifndef SHOGI_H
+#define SHOGI_H
+
+#include <stdio.h>
+#include "param.h"
+
+#if defined(_WIN32)
+
+# include <Winsock2.h>
+# define CONV_CDECL __cdecl
+# define SCKT_NULL INVALID_SOCKET
+typedef SOCKET sckt_t;
+
+#else
+
+# include <pthread.h>
+# include <sys/times.h>
+# define CONV_CDECL
+# define SCKT_NULL -1
+# define SOCKET_ERROR -1
+typedef int sckt_t;
+
+#endif
+
+/* Microsoft C/C++ */
+#if defined(_MSC_VER)
+
+# define _CRT_DISABLE_PERFCRIT_LOCKS
+# define UINT64_MAX ULLONG_MAX
+# define PRIu64 "I64u"
+# define PRIx64 "I64x"
+# define UINT64_C(u) ( u )
+
+# define restrict __restrict
+# define strtok_r strtok_s
+# define read _read
+# define strncpy( dst, src, len ) strncpy_s( dst, len, src, _TRUNCATE )
+# define snprintf( buf, size, fmt, ... ) \
+ _snprintf_s( buf, size, _TRUNCATE, fmt, __VA_ARGS__ )
+# define vsnprintf( buf, size, fmt, list ) \
+ _vsnprintf_s( buf, size, _TRUNCATE, fmt, list )
+typedef unsigned __int64 uint64_t;
+typedef volatile long lock_t;
+
+/* GNU C and Intel C/C++ on x86 and x86-64 */
+#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+
+# include <inttypes.h>
+# define restrict __restrict
+typedef volatile int lock_t;
+
+/* other targets. */
+#else
+
+# include <inttypes.h>
+typedef pthread_mutex_t lock_t;
+extern unsigned char aifirst_one[512];
+extern unsigned char ailast_one[512];
+
+#endif
+
+/*
+ #define BK_ULTRA_NARROW
+ #define BK_COM
+ #define BK_SMALL
+ #define NO_NULL_PRUNE
+ #define NO_STDOUT
+ #define DBG_EASY
+*/
+
+#if defined(CSASHOGI)
+# define NO_STDOUT
+# if ! defined(WIN32_PIPE)
+# define WIN32_PIPE
+# endif
+#endif
+
+#if defined(TLP)
+# define SHARE volatile
+# define SEARCH_ABORT ( root_abort || ptree->tlp_abort )
+#else
+# define SHARE
+# define SEARCH_ABORT root_abort
+#endif
+
+#define QUIES_PLY_LIMIT 7
+#define SHELL_H_LEN 7
+#define MAX_ANSWER 8
+#define PLY_INC 8
+#define PLY_MAX 48
+#define RAND_N 624
+#define TC_NMOVE 37U
+#define SEC_MARGIN 15U
+#define SEC_KEEP_ALIVE 180U
+#define TIME_RESPONSE 200U
+#define RESIGN_THRESHOLD ( ( MT_CAP_DRAGON * 5 ) / 8 )
+#define BNZ_VER "Feliz 0.0"
+
+#define REP_MAX_PLY 32
+#define REP_HIST_LEN 256
+
+#define EHASH_MASK 0x3fffffU /* occupies 32MB */
+
+#define MNJ_MASK 0xfffU
+
+#define HIST_SIZE 0x4000U
+#define HIST_INVALID 0xffffU
+#define HIST_MAX 0x1000U
+
+#define REJEC_MASK 0x0ffffU
+#define REJEC_MIN_DEPTH ( ( PLY_INC * 5 ) )
+
+#define EXT_RECAP1 ( ( PLY_INC * 1 ) / 4 )
+#define EXT_RECAP2 ( ( PLY_INC * 2 ) / 4 )
+#define EXT_ONEREP ( ( PLY_INC * 2 ) / 4 )
+#define EXT_CHECK ( ( PLY_INC * 4 ) / 4 )
+
+#define EFUTIL_MG1 ( ( MT_CAP_DRAGON * 2 ) / 8 )
+#define EFUTIL_MG2 ( ( MT_CAP_DRAGON * 2 ) / 8 )
+
+#define FMG_MG ( ( MT_CAP_DRAGON * 2 ) / 16 )
+#define FMG_MG_KING ( ( MT_CAP_DRAGON * 3 ) / 16 )
+#define FMG_MG_MT ( ( MT_CAP_DRAGON * 8 ) / 16 )
+#define FMG_MISC ( ( MT_CAP_DRAGON * 2 ) / 8 )
+#define FMG_CAP ( ( MT_CAP_DRAGON * 2 ) / 8 )
+#define FMG_DROP ( ( MT_CAP_DRAGON * 2 ) / 8 )
+#define FMG_MT ( ( MT_CAP_DRAGON * 2 ) / 8 )
+#define FMG_MISC_KING ( ( MT_CAP_DRAGON * 2 ) / 8 )
+#define FMG_CAP_KING ( ( MT_CAP_DRAGON * 2 ) / 8 )
+
+#define HASH_REG_HIST_LEN 256
+#define HASH_REG_MINDIFF ( ( MT_CAP_DRAGON * 1 ) / 8 )
+#define HASH_REG_THRESHOLD ( ( MT_CAP_DRAGON * 8 ) / 8 )
+
+#define FV_WINDOW 256
+#define FV_SCALE 32
+#define FV_PENALTY ( 0.2 / (double)FV_SCALE )
+
+#define MPV_MAX_PV 16
+
+#define TLP_MAX_THREADS 12
+#define TLP_NUM_WORK ( TLP_MAX_THREADS * 8 )
+
+#define TIME_CHECK_MIN_NODE 10000U
+#define TIME_CHECK_MAX_NODE 100000U
+
+#define SIZE_FILENAME 256
+#define SIZE_PLAYERNAME 256
+#define SIZE_MESSAGE 512
+#define SIZE_CMDLINE 512
+#define SIZE_CSALINE 512
+#define SIZE_CMDBUFFER 512
+
+#define IsMove(move) ( (move) & 0xffffffU )
+#define MOVE_NA 0x00000000U
+#define MOVE_PASS 0x01000000U
+#define MOVE_PONDER_FAILED 0xfe000000U
+#define MOVE_RESIGN 0xff000000U
+#define MOVE_CHK_SET 0x80000000U
+#define MOVE_CHK_CLEAR 0x40000000U
+
+#define MAX_LEGAL_MOVES 700
+#define MAX_LEGAL_EVASION 256
+#define MOVE_LIST_LEN 16384
+
+#define MAX_SIZE_SECTION 0xffff
+#define NUM_SECTION 0x4000
+
+#define MATERIAL (ptree->posi.material)
+#define HAND_B (ptree->posi.hand_black)
+#define HAND_W (ptree->posi.hand_white)
+
+#define BB_BOCCUPY (ptree->posi.b_occupied)
+#define BB_BTGOLD (ptree->posi.b_tgold)
+#define BB_B_HDK (ptree->posi.b_hdk)
+#define BB_B_BH (ptree->posi.b_bh)
+#define BB_B_RD (ptree->posi.b_rd)
+#define BB_BPAWN_ATK (ptree->posi.b_pawn_attacks)
+#define BB_BPAWN (ptree->posi.b_pawn)
+#define BB_BLANCE (ptree->posi.b_lance)
+#define BB_BKNIGHT (ptree->posi.b_knight)
+#define BB_BSILVER (ptree->posi.b_silver)
+#define BB_BGOLD (ptree->posi.b_gold)
+#define BB_BBISHOP (ptree->posi.b_bishop)
+#define BB_BROOK (ptree->posi.b_rook)
+#define BB_BKING (abb_mask[SQ_BKING])
+#define BB_BPRO_PAWN (ptree->posi.b_pro_pawn)
+#define BB_BPRO_LANCE (ptree->posi.b_pro_lance)
+#define BB_BPRO_KNIGHT (ptree->posi.b_pro_knight)
+#define BB_BPRO_SILVER (ptree->posi.b_pro_silver)
+#define BB_BHORSE (ptree->posi.b_horse)
+#define BB_BDRAGON (ptree->posi.b_dragon)
+
+#define BB_WOCCUPY (ptree->posi.w_occupied)
+#define BB_WTGOLD (ptree->posi.w_tgold)
+#define BB_W_HDK (ptree->posi.w_hdk)
+#define BB_W_BH (ptree->posi.w_bh)
+#define BB_W_RD (ptree->posi.w_rd)
+#define BB_WPAWN_ATK (ptree->posi.w_pawn_attacks)
+#define BB_WPAWN (ptree->posi.w_pawn)
+#define BB_WLANCE (ptree->posi.w_lance)
+#define BB_WKNIGHT (ptree->posi.w_knight)
+#define BB_WSILVER (ptree->posi.w_silver)
+#define BB_WGOLD (ptree->posi.w_gold)
+#define BB_WBISHOP (ptree->posi.w_bishop)
+#define BB_WROOK (ptree->posi.w_rook)
+#define BB_WKING (abb_mask[SQ_WKING])
+#define BB_WPRO_PAWN (ptree->posi.w_pro_pawn)
+#define BB_WPRO_LANCE (ptree->posi.w_pro_lance)
+#define BB_WPRO_KNIGHT (ptree->posi.w_pro_knight)
+#define BB_WPRO_SILVER (ptree->posi.w_pro_silver)
+#define BB_WHORSE (ptree->posi.w_horse)
+#define BB_WDRAGON (ptree->posi.w_dragon)
+
+#define OCCUPIED_FILE (ptree->posi.occupied_rl90)
+#define OCCUPIED_DIAG1 (ptree->posi.occupied_rr45)
+#define OCCUPIED_DIAG2 (ptree->posi.occupied_rl45)
+#define BOARD (ptree->posi.asquare)
+
+#define SQ_BKING (ptree->posi.isquare_b_king)
+#define SQ_WKING (ptree->posi.isquare_w_king)
+
+#define HASH_KEY (ptree->posi.hash_key)
+#define HASH_VALUE (ptree->sort_value[0])
+#define MOVE_CURR (ptree->current_move[ply])
+#define MOVE_LAST (ptree->current_move[ply-1])
+
+#define NullDepth(d) ( (d) < PLY_INC*26/4 ? (d)-PLY_INC*12/4 : \
+ ( (d) <= PLY_INC*30/4 ? PLY_INC*14/4 \
+ : (d)-PLY_INC*16/4) )
+
+#define LimitExtension(e,ply) if ( (e) && (ply) > 2 * iteration_depth ) { \
+ if ( (ply) < 4 * iteration_depth ) { \
+ e *= 4 * iteration_depth - (ply); \
+ e /= 2 * iteration_depth; \
+ } else { e = 0; } }
+
+#define Flip(turn) ((turn)^1)
+#define Inv(sq) (nsquare-1-sq)
+#define PcOnSq(k,i) pc_on_sq[k][(i)*((i)+3)/2]
+#define PcPcOnSq(k,i,j) pc_on_sq[k][(i)*((i)+1)/2+(j)]
+
+/*
+ xxxxxxxx xxxxxxxx xxx11111 pawn
+ xxxxxxxx xxxxxxxx 111xxxxx lance
+ xxxxxxxx xxxxx111 xxxxxxxx knight
+ xxxxxxxx xx111xxx xxxxxxxx silver
+ xxxxxxx1 11xxxxxx xxxxxxxx gold
+ xxxxx11x xxxxxxxx xxxxxxxx bishop
+ xxx11xxx xxxxxxxx xxxxxxxx rook
+ */
+#define I2HandPawn(hand) (((hand) >> 0) & 0x1f)
+#define I2HandLance(hand) (((hand) >> 5) & 0x07)
+#define I2HandKnight(hand) (((hand) >> 8) & 0x07)
+#define I2HandSilver(hand) (((hand) >> 11) & 0x07)
+#define I2HandGold(hand) (((hand) >> 14) & 0x07)
+#define I2HandBishop(hand) (((hand) >> 17) & 0x03)
+#define I2HandRook(hand) ((hand) >> 19)
+#define IsHandPawn(hand) ((hand) & 0x000001f)
+#define IsHandLance(hand) ((hand) & 0x00000e0)
+#define IsHandKnight(hand) ((hand) & 0x0000700)
+#define IsHandSilver(hand) ((hand) & 0x0003800)
+#define IsHandGold(hand) ((hand) & 0x001c000)
+#define IsHandBishop(hand) ((hand) & 0x0060000)
+#define IsHandRook(hand) ((hand) & 0x0180000)
+/*
+ xxxxxxxx xxxxxxxx x1111111 destination
+ xxxxxxxx xx111111 1xxxxxxx starting square or drop piece+nsquare-1
+ xxxxxxxx x1xxxxxx xxxxxxxx flag for promotion
+ xxxxx111 1xxxxxxx xxxxxxxx piece to move
+ x1111xxx xxxxxxxx xxxxxxxx captured piece
+ */
+#define To2Move(to) ((unsigned int)(to) << 0)
+#define From2Move(from) ((unsigned int)(from) << 7)
+#define Drop2Move(piece) ((nsquare-1+(piece)) << 7)
+#define Drop2From(piece) (nsquare-1+(piece))
+#define FLAG_PROMO (1U << 14)
+#define Piece2Move(piece) ((piece) << 15)
+#define Cap2Move(piece) ((piece) << 19)
+#define I2To(move) (((move) >> 0) & 0x007fU)
+#define I2From(move) (((move) >> 7) & 0x007fU)
+#define I2FromTo(move) (((move) >> 0) & 0x3fffU)
+#define I2IsPromote(move) ((move) & FLAG_PROMO)
+#define I2PieceMove(move) (((move) >> 15) & 0x000fU)
+#define UToFromToPromo(u) ( (u) & 0x7ffffU )
+#define UToCap(u) (((u) >> 19) & 0x000fU)
+#define From2Drop(from) ((from)-nsquare+1)
+
+
+#define BBIni(bb) (bb).p[0] = (bb).p[1] = (bb).p[2] = 0
+#define BBToU(bb) ((bb).p[0] | (bb).p[1] | (bb).p[2])
+#define BBToUShift(bb) ((bb).p[0]<<2 | (bb).p[1]<<1 | (bb).p[2])
+#define PopuCount(bb) popu_count012( bb.p[0], bb.p[1], bb.p[2] )
+#define FirstOne(bb) first_one012( bb.p[0], bb.p[1], bb.p[2] )
+#define LastOne(bb) last_one210( bb.p[2], bb.p[1], bb.p[0] )
+
+#define BBCmp(bb1,bb2) ( (bb1).p[0] != (bb2).p[0] \
+ || (bb1).p[1] != (bb2).p[1] \
+ || (bb1).p[2] != (bb2).p[2] )
+
+#define BBNot(bb,bb1) (bb).p[0] = ~(bb1).p[0], \
+ (bb).p[1] = ~(bb1).p[1], \
+ (bb).p[2] = ~(bb1).p[2]
+
+#define BBOr(bb,bb1,bb2) (bb).p[0] = (bb1).p[0] | (bb2).p[0], \
+ (bb).p[1] = (bb1).p[1] | (bb2).p[1], \
+ (bb).p[2] = (bb1).p[2] | (bb2).p[2]
+
+#define BBAnd(bb,bb1,bb2) (bb).p[0] = (bb1).p[0] & (bb2).p[0], \
+ (bb).p[1] = (bb1).p[1] & (bb2).p[1], \
+ (bb).p[2] = (bb1).p[2] & (bb2).p[2]
+
+#define BBXor(bb,b1,b2) (bb).p[0] = (b1).p[0] ^ (b2).p[0], \
+ (bb).p[1] = (b1).p[1] ^ (b2).p[1], \
+ (bb).p[2] = (b1).p[2] ^ (b2).p[2]
+
+#define BBAndOr(bb,bb1,bb2) (bb).p[0] |= (bb1).p[0] & (bb2).p[0], \
+ (bb).p[1] |= (bb1).p[1] & (bb2).p[1], \
+ (bb).p[2] |= (bb1).p[2] & (bb2).p[2]
+
+#define BBNotAnd(bb,bb1) bb.p[0] &= ~bb1.p[0]; \
+ bb.p[1] &= ~bb1.p[1]; \
+ bb.p[2] &= ~bb1.p[2]
+
+#define BBContractShift(bb1,bb2) ( ( (bb1).p[0] & (bb2).p[0] ) << 2 \
+ | ( (bb1).p[1] & (bb2).p[1] ) << 1 \
+ | ( (bb1).p[2] & (bb2).p[2] ) )
+
+#define BBContract(bb1,bb2) ( ( (bb1).p[0] & (bb2).p[0] ) \
+ | ( (bb1).p[1] & (bb2).p[1] ) \
+ | ( (bb1).p[2] & (bb2).p[2] ) )
+
+#define Xor(i,bb) (bb).p[0] ^= abb_mask[i].p[0], \
+ (bb).p[1] ^= abb_mask[i].p[1], \
+ (bb).p[2] ^= abb_mask[i].p[2]
+
+#define XorFile(i,bb) (bb).p[0] ^= abb_mask_rl90[i].p[0], \
+ (bb).p[1] ^= abb_mask_rl90[i].p[1], \
+ (bb).p[2] ^= abb_mask_rl90[i].p[2]
+
+#define XorDiag1(i,bb) (bb).p[0] ^= abb_mask_rr45[i].p[0], \
+ (bb).p[1] ^= abb_mask_rr45[i].p[1], \
+ (bb).p[2] ^= abb_mask_rr45[i].p[2]
+
+#define XorDiag2(i,bb) (bb).p[0] ^= abb_mask_rl45[i].p[0], \
+ (bb).p[1] ^= abb_mask_rl45[i].p[1], \
+ (bb).p[2] ^= abb_mask_rl45[i].p[2]
+
+#define SetClear(bb) (bb).p[0] ^= (bb_set_clear.p[0]), \
+ (bb).p[1] ^= (bb_set_clear.p[1]), \
+ (bb).p[2] ^= (bb_set_clear.p[2])
+
+#define SetClearFile(i1,i2,bb) \
+ (bb).p[0] ^= ((abb_mask_rl90[i1].p[0])|(abb_mask_rl90[i2].p[0])), \
+ (bb).p[1] ^= ((abb_mask_rl90[i1].p[1])|(abb_mask_rl90[i2].p[1])), \
+ (bb).p[2] ^= ((abb_mask_rl90[i1].p[2])|(abb_mask_rl90[i2].p[2]))
+
+#define SetClearDiag1(i1,i2,bb) \
+ (bb).p[0] ^= ((abb_mask_rr45[i1].p[0])|(abb_mask_rr45[i2].p[0])), \
+ (bb).p[1] ^= ((abb_mask_rr45[i1].p[1])|(abb_mask_rr45[i2].p[1])), \
+ (bb).p[2] ^= ((abb_mask_rr45[i1].p[2])|(abb_mask_rr45[i2].p[2]))
+
+#define SetClearDiag2(i1,i2,bb) \
+ (bb).p[0] ^= ((abb_mask_rl45[i1].p[0])|(abb_mask_rl45[i2].p[0])), \
+ (bb).p[1] ^= ((abb_mask_rl45[i1].p[1])|(abb_mask_rl45[i2].p[1])), \
+ (bb).p[2] ^= ((abb_mask_rl45[i1].p[2])|(abb_mask_rl45[i2].p[2]))
+
+#define AttackFile(i) (abb_file_attacks[i] \
+ [((ptree->posi.occupied_rl90.p[aslide[i].irl90]) \
+ >> aslide[i].srl90) & 0x7f])
+
+#define AttackRank(i) (ai_rook_attacks_r0[i] \
+ [((ptree->posi.b_occupied.p[aslide[i].ir0] \
+ |ptree->posi.w_occupied.p[aslide[i].ir0]) \
+ >> aslide[i].sr0) & 0x7f ])
+
+#define AttackDiag1(i) \
+ (abb_bishop_attacks_rr45[i] \
+ [((ptree->posi.occupied_rr45.p[aslide[i].irr45]) \
+ >> aslide[i].srr45) & 0x7f])
+
+#define AttackDiag2(i) \
+ (abb_bishop_attacks_rl45[i] \
+ [((ptree->posi.occupied_rl45.p[aslide[i].irl45]) \
+ >> aslide[i].srl45) & 0x7f])
+
+#define BishopAttack0(i) ( AttackDiag1(i).p[0] | AttackDiag2(i).p[0] )
+#define BishopAttack1(i) ( AttackDiag1(i).p[1] | AttackDiag2(i).p[1] )
+#define BishopAttack2(i) ( AttackDiag1(i).p[2] | AttackDiag2(i).p[2] )
+#define AttackBLance(bb,i) BBAnd( bb, abb_minus_rays[i], AttackFile(i) )
+#define AttackWLance(bb,i) BBAnd( bb, abb_plus_rays[i], AttackFile(i) )
+#define AttackHorse(bb,i) AttackBishop(bb,i); BBOr(bb,bb,abb_king_attacks[i])
+#define AttackDragon(bb,i) AttackRook(bb,i); BBOr(bb,bb,abb_king_attacks[i])
+
+#define InCheck(turn) \
+ ( (turn) ? is_white_attacked( ptree, SQ_WKING ) \
+ : is_black_attacked( ptree, SQ_BKING ) )
+
+#define MakeMove(turn,move,ply) \
+ ( (turn) ? make_move_w( ptree, move, ply ) \
+ : make_move_b( ptree, move, ply ) )
+
+#define UnMakeMove(turn,move,ply) \
+ ( (turn) ? unmake_move_w( ptree, move, ply ) \
+ : unmake_move_b( ptree, move, ply ) )
+
+#define IsMoveCheck( ptree, turn, move ) \
+ ( (turn) ? is_move_check_w( ptree, move ) \
+ : is_move_check_b( ptree, move ) )
+
+#define GenCaptures(turn,pmove) ( (turn) ? w_gen_captures( ptree, pmove ) \
+ : b_gen_captures( ptree, pmove ) )
+
+#define GenNoCaptures(turn,pmove) \
+ ( (turn) ? w_gen_nocaptures( ptree, pmove ) \
+ : b_gen_nocaptures( ptree, pmove ) )
+
+#define GenDrop(turn,pmove) ( (turn) ? w_gen_drop( ptree, pmove ) \
+ : b_gen_drop( ptree, pmove ) )
+
+#define GenCapNoProEx2(turn,pmove) \
+ ( (turn) ? w_gen_cap_nopro_ex2( ptree, pmove ) \
+ : b_gen_cap_nopro_ex2( ptree, pmove ) )
+
+#define GenNoCapNoProEx2(turn,pmove) \
+ ( (turn) ? w_gen_nocap_nopro_ex2( ptree, pmove ) \
+ : b_gen_nocap_nopro_ex2( ptree, pmove ) )
+
+#define GenEvasion(turn,pmove) \
+ ( (turn) ? w_gen_evasion( ptree, pmove ) \
+ : b_gen_evasion( ptree, pmove ) )
+
+#define GenCheck(turn,pmove) \
+ ( (turn) ? w_gen_checks( ptree, pmove ) \
+ : b_gen_checks( ptree, pmove ) )
+
+#define IsMateIn1Ply(turn) \
+ ( (turn) ? is_w_mate_in_1ply( ptree ) \
+ : is_b_mate_in_1ply( ptree ) )
+
+#define IsDiscoverBK(from,to) \
+ idirec = (int)adirec[SQ_BKING][from], \
+ ( idirec && ( idirec!=(int)adirec[SQ_BKING][to] ) \
+ && is_pinned_on_black_king( ptree, from, idirec ) )
+
+#define IsDiscoverWK(from,to) \
+ idirec = (int)adirec[SQ_WKING][from], \
+ ( idirec && ( idirec!=(int)adirec[SQ_WKING][to] ) \
+ && is_pinned_on_white_king( ptree, from, idirec ) )
+#define IsMateWPawnDrop(ptree,to) ( BOARD[(to)+9] == king \
+ && is_mate_w_pawn_drop( ptree, to ) )
+
+#define IsMateBPawnDrop(ptree,to) ( BOARD[(to)-9] == -king \
+ && is_mate_b_pawn_drop( ptree, to ) )
+
+enum { b0000, b0001, b0010, b0011, b0100, b0101, b0110, b0111,
+ b1000, b1001, b1010, b1011, b1100, b1101, b1110, b1111 };
+
+enum { A9 = 0, B9, C9, D9, E9, F9, G9, H9, I9,
+ A8, B8, C8, D8, E8, F8, G8, H8, I8,
+ A7, B7, C7, D7, E7, F7, G7, H7, I7,
+ A6, B6, C6, D6, E6, F6, G6, H6, I6,
+ A5, B5, C5, D5, E5, F5, G5, H5, I5,
+ A4, B4, C4, D4, E4, F4, G4, H4, I4,
+ A3, B3, C3, D3, E3, F3, G3, H3, I3,
+ A2, B2, C2, D2, E2, F2, G2, H2, I2,
+ A1, B1, C1, D1, E1, F1, G1, H1, I1 };
+
+enum { promote = 8, empty = 0,
+ pawn, lance, knight, silver, gold, bishop, rook, king, pro_pawn,
+ pro_lance, pro_knight, pro_silver, piece_null, horse, dragon };
+
+enum { npawn_max = 18, nlance_max = 4, nknight_max = 4, nsilver_max = 4,
+ ngold_max = 4, nbishop_max = 2, nrook_max = 2, nking_max = 2 };
+
+enum { rank1 = 0, rank2, rank3, rank4, rank5, rank6, rank7, rank8, rank9 };
+enum { file1 = 0, file2, file3, file4, file5, file6, file7, file8, file9 };
+
+enum { nhand = 7, nfile = 9, nrank = 9, nsquare = 81 };
+
+enum { mask_file1 = (( 1U << 18 | 1U << 9 | 1U ) << 8) };
+
+enum { flag_diag1 = b0001, flag_plus = b0010 };
+
+enum { score_draw = 1,
+ score_max_eval = 30000,
+ score_mate1ply = 32598,
+ score_inferior = 32599,
+ score_bound = 32600,
+ score_foul = 32600 };
+
+enum { phase_hash = b0001,
+ phase_killer1 = b0001 << 1,
+ phase_killer2 = b0010 << 1,
+ phase_killer = b0011 << 1,
+ phase_cap1 = b0001 << 3,
+ phase_cap_misc = b0010 << 3,
+ phase_cap = b0011 << 3,
+ phase_history1 = b0001 << 5,
+ phase_history2 = b0010 << 5,
+ phase_history = b0011 << 5,
+ phase_misc = b0100 << 5 };
+
+enum { next_move_hash = 0, next_move_capture, next_move_history2,
+ next_move_misc };
+
+/* next_evasion_hash should be the same as next_move_hash */
+enum { next_evasion_hash = 0, next_evasion_genall, next_evasion_misc };
+
+enum { next_quies_gencap, next_quies_captures, next_quies_misc };
+
+enum { no_rep = 0, four_fold_rep, perpetual_check, perpetual_check2,
+ black_superi_rep, white_superi_rep, hash_hit, prev_solution, book_hit,
+ pv_fail_high, mate_search };
+
+enum { record_misc, record_eof, record_next, record_resign, record_drawn,
+ record_error };
+
+enum { black = 0, white = 1 };
+
+enum { direc_misc = b0000,
+ direc_file = b0010, /* | */
+ direc_rank = b0011, /* - */
+ direc_diag1 = b0100, /* / */
+ direc_diag2 = b0101, /* \ */
+ flag_cross = b0010,
+ flag_diag = b0100 };
+
+enum { value_null = b0000,
+ value_upper = b0001,
+ value_lower = b0010,
+ value_exact = b0011,
+ flag_value_up_exact = b0001,
+ flag_value_low_exact = b0010,
+ node_do_null = b0100,
+ node_do_recap = b1000,
+ node_do_mate = b0001 << 4,
+ node_mate_threat = b0010 << 4, /* <- don't change it */
+ node_do_futile = b0100 << 4,
+ state_node_end };
+/* note: maximum bits are 8. tlp_state_node uses type unsigned char. */
+
+enum { flag_from_ponder = b0001,
+ flag_refer_rest = b0010 };
+
+enum { flag_time = b0001,
+ flag_history = b0010,
+ flag_rep = b0100,
+ flag_detect_hang = b1000,
+ flag_rejections = b0001 << 4,
+ flag_nomake_move = b0010 << 4,
+ flag_nofmargin = b0100 << 4 };
+
+/* flags represent status of root move */
+enum { flag_searched = b0001,
+ flag_failhigh = b0010,
+ flag_faillow = b0100,
+ flag_first = b1000 };
+
+enum { flag_mated = b0001,
+ flag_resigned = b0010,
+ flag_drawn = b0100,
+ flag_suspend = b1000,
+ mask_game_end = b1111,
+ flag_quit = b0001 << 4,
+ flag_puzzling = b0010 << 4,
+ flag_pondering = b0100 << 4,
+ flag_thinking = b1000 << 4,
+ flag_problem = b0001 << 8,
+ flag_move_now = b0010 << 8,
+ flag_quit_ponder = b0100 << 8,
+ flag_search_error = b0001 << 12,
+ flag_quiet = b0010 << 12,
+ flag_reverse = b0100 << 12,
+ flag_narrow_book = b1000 << 12,
+ flag_time_extendable = b0001 << 16,
+ flag_learning = b0010 << 16,
+ flag_nobeep = b0100 << 16,
+ flag_nostress = b1000 << 16,
+ flag_nopeek = b0001 << 20,
+ flag_noponder = b0010 << 20,
+ flag_noprompt = b0100 << 20 };
+
+
+enum { flag_hand_pawn = 1 << 0,
+ flag_hand_lance = 1 << 5,
+ flag_hand_knight = 1 << 8,
+ flag_hand_silver = 1 << 11,
+ flag_hand_gold = 1 << 14,
+ flag_hand_bishop = 1 << 17,
+ flag_hand_rook = 1 << 19 };
+
+enum { f_hand_pawn = 0,
+ e_hand_pawn = 19,
+ f_hand_lance = 38,
+ e_hand_lance = 43,
+ f_hand_knight = 48,
+ e_hand_knight = 53,
+ f_hand_silver = 58,
+ e_hand_silver = 63,
+ f_hand_gold = 68,
+ e_hand_gold = 73,
+ f_hand_bishop = 78,
+ e_hand_bishop = 81,
+ f_hand_rook = 84,
+ e_hand_rook = 87,
+ fe_hand_end = 90,
+ f_pawn = 81,
+ e_pawn = 162,
+ f_lance = 225,
+ e_lance = 306,
+ f_knight = 360,
+ e_knight = 441,
+ f_silver = 504,
+ e_silver = 585,
+ f_gold = 666,
+ e_gold = 747,
+ f_bishop = 828,
+ e_bishop = 909,
+ f_horse = 990,
+ e_horse = 1071,
+ f_rook = 1152,
+ e_rook = 1233,
+ f_dragon = 1314,
+ e_dragon = 1395,
+ fe_end = 1476,
+
+ kkp_hand_pawn = 0,
+ kkp_hand_lance = 19,
+ kkp_hand_knight = 24,
+ kkp_hand_silver = 29,
+ kkp_hand_gold = 34,
+ kkp_hand_bishop = 39,
+ kkp_hand_rook = 42,
+ kkp_hand_end = 45,
+ kkp_pawn = 36,
+ kkp_lance = 108,
+ kkp_knight = 171,
+ kkp_silver = 252,
+ kkp_gold = 333,
+ kkp_bishop = 414,
+ kkp_horse = 495,
+ kkp_rook = 576,
+ kkp_dragon = 657,
+ kkp_end = 738 };
+
+enum { pos_n = fe_end * ( fe_end + 1 ) / 2 };
+
+typedef struct { unsigned int p[3]; } bitboard_t;
+
+typedef struct { bitboard_t gold, silver, knight, lance; } check_table_t;
+
+#if ! defined(MINIMUM)
+typedef struct { fpos_t fpos; unsigned int games, moves, lines; } rpos_t;
+typedef struct {
+ double pawn, lance, knight, silver, gold, bishop, rook;
+ double pro_pawn, pro_lance, pro_knight, pro_silver, horse, dragon;
+ float pc_on_sq[nsquare][fe_end*(fe_end+1)/2];
+ float kkp[nsquare][nsquare][kkp_end];
+} param_t;
+#endif
+
+typedef enum { mode_write, mode_read_write, mode_read } record_mode_t;
+
+typedef struct { uint64_t word1, word2; } trans_entry_t;
+typedef struct { trans_entry_t prefer, always[2]; } trans_table_t;
+typedef struct { int count; unsigned int cnst[2], vec[RAND_N]; }rand_work_t;
+
+typedef struct {
+ uint64_t root;
+ SHARE uint64_t sibling;
+} rejections_t;
+
+typedef struct {
+ int no1_value, no2_value;
+ unsigned int no1, no2;
+} move_killer_t;
+
+typedef struct { unsigned int no1, no2; } killer_t;
+
+typedef struct {
+ union { char str_move[ MAX_ANSWER ][ 8 ]; } info;
+ char str_name1[ SIZE_PLAYERNAME ];
+ char str_name2[ SIZE_PLAYERNAME ];
+ FILE *pf;
+ unsigned int games, moves, lines;
+} record_t;
+
+typedef struct {
+ unsigned int a[PLY_MAX];
+ unsigned char type;
+ unsigned char length;
+ unsigned char depth;
+} pv_t;
+
+typedef struct {
+ unsigned char ir0, sr0;
+ unsigned char irl90, srl90;
+ unsigned char irl45, srl45;
+ unsigned char irr45, srr45;
+} slide_tbl_t;
+
+
+typedef struct {
+ uint64_t hash_key;
+ bitboard_t b_occupied, w_occupied;
+ bitboard_t occupied_rl90, occupied_rl45, occupied_rr45;
+ bitboard_t b_hdk, w_hdk;
+ bitboard_t b_tgold, w_tgold;
+ bitboard_t b_bh, w_bh;
+ bitboard_t b_rd, w_rd;
+ bitboard_t b_pawn_attacks, w_pawn_attacks;
+ bitboard_t b_lance, w_lance;
+ bitboard_t b_knight, w_knight;
+ bitboard_t b_silver, w_silver;
+ bitboard_t b_bishop, w_bishop;
+ bitboard_t b_rook, w_rook;
+ bitboard_t b_horse, w_horse;
+ bitboard_t b_dragon, w_dragon;
+ bitboard_t b_pawn, w_pawn;
+ bitboard_t b_gold, w_gold;
+ bitboard_t b_pro_pawn, w_pro_pawn;
+ bitboard_t b_pro_lance, w_pro_lance;
+ bitboard_t b_pro_knight, w_pro_knight;
+ bitboard_t b_pro_silver, w_pro_silver;
+ unsigned int hand_black, hand_white;
+ int material;
+ signed char asquare[nsquare];
+ unsigned char isquare_b_king, isquare_w_king;
+} posi_t;
+
+
+typedef struct {
+ unsigned int hand_black, hand_white;
+ char turn_to_move;
+ signed char asquare[nsquare];
+} min_posi_t;
+
+typedef struct {
+ uint64_t nodes;
+ unsigned int move, status;
+} root_move_t;
+
+typedef struct {
+ unsigned int *move_last;
+ unsigned int move_cap1;
+ unsigned int move_cap2;
+ int phase_done, next_phase, remaining, value_cap1, value_cap2;
+} next_move_t;
+
+/* data: 31 1bit flag_learned */
+/* 30 1bit is_flip */
+/* 15 16bit value */
+typedef struct {
+ uint64_t key_book;
+ unsigned int key_responsible, key_probed, key_played;
+ unsigned int hand_responsible, hand_probed, hand_played;
+ unsigned int move_played, move_responsible, move_probed, data;
+} history_book_learn_t;
+
+typedef struct tree tree_t;
+struct tree {
+ posi_t posi;
+ uint64_t rep_board_list[ REP_HIST_LEN ];
+ uint64_t node_searched;
+ unsigned int *move_last[ PLY_MAX ];
+ next_move_t anext_move[ PLY_MAX ];
+ pv_t pv[ PLY_MAX ];
+ move_killer_t amove_killer[ PLY_MAX ];
+ unsigned int null_pruning_done;
+ unsigned int null_pruning_tried;
+ unsigned int check_extension_done;
+ unsigned int recap_extension_done;
+ unsigned int onerp_extension_done;
+ unsigned int neval_called;
+ unsigned int nquies_called;
+ unsigned int nfour_fold_rep;
+ unsigned int nperpetual_check;
+ unsigned int nsuperior_rep;
+ unsigned int nrep_tried;
+ unsigned int nreject_tried;
+ unsigned int nreject_done;
+ unsigned int ntrans_always_hit;
+ unsigned int ntrans_prefer_hit;
+ unsigned int ntrans_probe;
+ unsigned int ntrans_exact;
+ unsigned int ntrans_lower;
+ unsigned int ntrans_upper;
+ unsigned int ntrans_superior_hit;
+ unsigned int ntrans_inferior_hit;
+ unsigned int fail_high;
+ unsigned int fail_high_first;
+ unsigned int rep_hand_list[ REP_HIST_LEN ];
+ unsigned int amove_hash[ PLY_MAX ];
+ unsigned int amove[ MOVE_LIST_LEN ];
+ unsigned int current_move[ PLY_MAX ];
+ killer_t killers[ PLY_MAX ];
+ unsigned int hist_nmove[ PLY_MAX ];
+ unsigned int hist_move[ PLY_MAX ][ MAX_LEGAL_MOVES ];
+ int sort_value[ MAX_LEGAL_MOVES ];
+ unsigned short hist_tried[ HIST_SIZE ];
+ unsigned short hist_good[ HIST_SIZE ];
+ short save_material[ PLY_MAX ];
+ short stand_pat[ PLY_MAX+1 ];
+ unsigned char nsuc_check[ PLY_MAX+1 ];
+#if defined(TLP)
+ struct tree *tlp_ptrees_sibling[ TLP_MAX_THREADS ];
+ struct tree *tlp_ptree_parent;
+ lock_t tlp_lock;
+ volatile int tlp_abort;
+ volatile int tlp_used;
+ unsigned short tlp_slot;
+ short tlp_beta;
+ short tlp_best;
+ volatile unsigned char tlp_nsibling;
+ unsigned char tlp_depth;
+ unsigned char tlp_state_node;
+ unsigned char tlp_id;
+ char tlp_turn;
+ char tlp_ply;
+#endif
+};
+
+
+extern SHARE unsigned int game_status;
+extern history_book_learn_t history_book_learn[ HASH_REG_HIST_LEN ];
+
+extern int npawn_box;
+extern int nlance_box;
+extern int nknight_box;
+extern int nsilver_box;
+extern int ngold_box;
+extern int nbishop_box;
+extern int nrook_box;
+
+extern unsigned int ponder_move_list[ MAX_LEGAL_MOVES ];
+extern unsigned int ponder_move;
+extern int ponder_nmove;
+
+extern root_move_t root_move_list[ MAX_LEGAL_MOVES ];
+extern SHARE int root_abort;
+extern int root_nrep;
+extern int root_nmove;
+extern int root_value;
+extern int root_alpha;
+extern int root_beta;
+extern int root_turn;
+extern int root_move_cap;
+extern int root_nfail_high;
+extern int root_nfail_low;
+extern int resign_threshold;
+extern int n_nobook_move;
+
+extern uint64_t node_limit;
+extern unsigned int node_per_second;
+extern unsigned int node_next_signal;
+extern unsigned int node_last_check;
+
+extern unsigned int hash_mask;
+extern int trans_table_age;
+
+extern pv_t last_pv;
+extern pv_t last_pv_save;
+extern int last_root_value;
+extern int last_root_value_save;
+
+extern SHARE trans_table_t *ptrans_table;
+extern trans_table_t *ptrans_table_orig;
+extern int log2_ntrans_table;
+
+extern int depth_limit;
+
+extern unsigned int time_last_result;
+extern unsigned int time_last_eff_search;
+extern unsigned int time_last_search;
+extern unsigned int time_last_check;
+extern unsigned int time_turn_start;
+extern unsigned int time_start;
+extern unsigned int time_max_limit;
+extern unsigned int time_limit;
+extern unsigned int time_response;
+extern unsigned int sec_limit;
+extern unsigned int sec_limit_up;
+extern unsigned int sec_limit_depth;
+extern unsigned int sec_elapsed;
+extern unsigned int sec_b_total;
+extern unsigned int sec_w_total;
+
+extern record_t record_problems;
+extern record_t record_game;
+extern FILE *pf_book;
+extern FILE *pf_hash;
+extern int irecord_game;
+
+extern short p_value[31];
+extern short pc_on_sq[nsquare][fe_end*(fe_end+1)/2];
+extern short kkp[nsquare][nsquare][kkp_end];
+
+extern uint64_t ehash_tbl[ EHASH_MASK + 1 ];
+extern unsigned char hash_rejections_parent[ REJEC_MASK+1 ];
+extern rejections_t hash_rejections[ REJEC_MASK+1 ];
+extern rand_work_t rand_work;
+extern slide_tbl_t aslide[ nsquare ];
+extern bitboard_t abb_b_knight_attacks[ nsquare ];
+extern bitboard_t abb_b_silver_attacks[ nsquare ];
+extern bitboard_t abb_b_gold_attacks[ nsquare ];
+extern bitboard_t abb_w_knight_attacks[ nsquare ];
+extern bitboard_t abb_w_silver_attacks[ nsquare ];
+extern bitboard_t abb_w_gold_attacks[ nsquare ];
+extern bitboard_t abb_king_attacks[ nsquare ];
+extern bitboard_t abb_obstacle[ nsquare ][ nsquare ];
+extern bitboard_t abb_bishop_attacks_rl45[ nsquare ][ 128 ];
+extern bitboard_t abb_bishop_attacks_rr45[ nsquare ][ 128 ];
+extern bitboard_t abb_file_attacks[ nsquare ][ 128 ];
+extern bitboard_t abb_mask[ nsquare ];
+extern bitboard_t abb_mask_rl90[ nsquare ];
+extern bitboard_t abb_mask_rl45[ nsquare ];
+extern bitboard_t abb_mask_rr45[ nsquare ];
+extern bitboard_t abb_plus_rays[ nsquare ];
+extern bitboard_t abb_minus_rays[ nsquare ];
+extern uint64_t b_pawn_rand[ nsquare ];
+extern uint64_t b_lance_rand[ nsquare ];
+extern uint64_t b_knight_rand[ nsquare ];
+extern uint64_t b_silver_rand[ nsquare ];
+extern uint64_t b_gold_rand[ nsquare ];
+extern uint64_t b_bishop_rand[ nsquare ];
+extern uint64_t b_rook_rand[ nsquare ];
+extern uint64_t b_king_rand[ nsquare ];
+extern uint64_t b_pro_pawn_rand[ nsquare ];
+extern uint64_t b_pro_lance_rand[ nsquare ];
+extern uint64_t b_pro_knight_rand[ nsquare ];
+extern uint64_t b_pro_silver_rand[ nsquare ];
+extern uint64_t b_horse_rand[ nsquare ];
+extern uint64_t b_dragon_rand[ nsquare ];
+extern uint64_t b_hand_pawn_rand[ npawn_max ];
+extern uint64_t b_hand_lance_rand[ nlance_max ];
+extern uint64_t b_hand_knight_rand[ nknight_max ];
+extern uint64_t b_hand_silver_rand[ nsilver_max ];
+extern uint64_t b_hand_gold_rand[ ngold_max ];
+extern uint64_t b_hand_bishop_rand[ nbishop_max ];
+extern uint64_t b_hand_rook_rand[ nrook_max ];
+extern uint64_t w_pawn_rand[ nsquare ];
+extern uint64_t w_lance_rand[ nsquare ];
+extern uint64_t w_knight_rand[ nsquare ];
+extern uint64_t w_silver_rand[ nsquare ];
+extern uint64_t w_gold_rand[ nsquare ];
+extern uint64_t w_bishop_rand[ nsquare ];
+extern uint64_t w_rook_rand[ nsquare ];
+extern uint64_t w_king_rand[ nsquare ];
+extern uint64_t w_pro_pawn_rand[ nsquare ];
+extern uint64_t w_pro_lance_rand[ nsquare ];
+extern uint64_t w_pro_knight_rand[ nsquare ];
+extern uint64_t w_pro_silver_rand[ nsquare ];
+extern uint64_t w_horse_rand[ nsquare ];
+extern uint64_t w_dragon_rand[ nsquare ];
+extern uint64_t w_hand_pawn_rand[ npawn_max ];
+extern uint64_t w_hand_lance_rand[ nlance_max ];
+extern uint64_t w_hand_knight_rand[ nknight_max ];
+extern uint64_t w_hand_silver_rand[ nsilver_max ];
+extern uint64_t w_hand_gold_rand[ ngold_max ];
+extern uint64_t w_hand_bishop_rand[ nbishop_max ];
+extern uint64_t w_hand_rook_rand[ nrook_max ];
+extern unsigned int ai_rook_attacks_r0[ nsquare ][ 128 ];
+extern unsigned int move_evasion_pchk;
+extern int p_value_ex[31];
+extern int benefit2promo[15];
+extern int easy_abs;
+extern int easy_min;
+extern int easy_max;
+extern int easy_value;
+extern SHARE int fmg_misc;
+extern SHARE int fmg_cap;
+extern SHARE int fmg_drop;
+extern SHARE int fmg_mt;
+extern SHARE int fmg_misc_king;
+extern SHARE int fmg_cap_king;
+extern int iteration_depth;
+extern unsigned char book_section[ MAX_SIZE_SECTION+1 ];
+extern unsigned char adirec[nsquare][nsquare];
+extern unsigned char is_same[16][16];
+extern char str_message[ SIZE_MESSAGE ];
+extern char str_cmdline[ SIZE_CMDLINE ];
+extern char str_buffer_cmdline[ SIZE_CMDBUFFER ];
+extern const char *str_error;
+
+extern const char *astr_table_piece[ 16 ];
+extern const char *str_resign;
+extern const char *str_repetition;
+extern const char *str_jishogi;
+extern const char *str_record_error;
+extern const char *str_unexpect_eof;
+extern const char *str_ovrflw_line;
+extern const char *str_warning;
+extern const char *str_on;
+extern const char *str_off;
+extern const char *str_book;
+extern const char *str_hash;
+extern const char *str_fv;
+extern const char *str_book_error;
+extern const char *str_perpet_check;
+extern const char *str_bad_cmdline;
+extern const char *str_busy_think;
+extern const char *str_bad_record;
+extern const char *str_bad_board;
+extern const char *str_delimiters;
+extern const char *str_fmt_line;
+extern const char *str_illegal_move;
+extern const char *str_double_pawn;
+extern const char *str_mate_drppawn;
+extern const char *str_fopen_error;
+extern const char *str_game_ended;
+extern const char *str_io_error;
+extern const char *str_spaces;
+extern const char *str_king_hang;
+#if defined(CSA_LAN)
+extern const char *str_server_err;
+#endif
+extern const char *str_myname;
+extern const char *str_version;
+extern const min_posi_t min_posi_no_handicap;
+extern const short aipos[31];
+extern const char ach_turn[2];
+extern const char ashell_h[ SHELL_H_LEN ];
+extern const unsigned char aifile[ nsquare ];
+extern const unsigned char airank[ nsquare ];
+
+void pv_close( tree_t * restrict ptree, int ply, int type );
+void pv_copy( tree_t * restrict ptree, int ply );
+void set_derivative_param( void );
+void set_search_limit_time( int turn );
+void ehash_clear( void );
+void hash_store_pv( const tree_t * restrict ptree, unsigned int move,
+ int turn );
+void check_futile_score_quies( const tree_t * restrict ptree,
+ unsigned int move, int old_val, int new_val,
+ int turn );
+void out_file( FILE *pf, const char *format, ... );
+void out_warning( const char *format, ... );
+void out_error( const char *format, ... );
+void show_prompt( void );
+void make_move_w( tree_t * restrict ptree, unsigned int move, int ply );
+void make_move_b( tree_t * restrict ptree, unsigned int move, int ply );
+void unmake_move_b( tree_t * restrict ptree, unsigned int move, int ply );
+void unmake_move_w( tree_t * restrict ptree, unsigned int move, int ply );
+void ini_rand( unsigned int s );
+void out_CSA( tree_t * restrict ptree, record_t *pr, unsigned int move );
+void out_pv( tree_t * restrict ptree, int value, int turn, unsigned int time );
+void hash_store( const tree_t * restrict ptree, int ply, int depth, int turn,
+ int value_type, int value, unsigned int move,
+ unsigned int state_node );
+void *memory_alloc( size_t nbytes );
+void unmake_move_root( tree_t * restrict ptree, unsigned int move );
+void add_rejections_root( tree_t * restrict ptree, unsigned int move_made );
+void sub_rejections_root( tree_t * restrict ptree, unsigned int move_made );
+void add_rejections( tree_t * restrict ptree, int turn, int ply );
+void sub_rejections( tree_t * restrict ptree, int turn, int ply );
+void adjust_time( unsigned int elapsed_new, int turn );
+int popu_count012( unsigned int u0, unsigned int u1, unsigned int u2 );
+int first_one012( unsigned int u0, unsigned int u1, unsigned int u2 );
+int last_one210( unsigned int u2, unsigned int u1, unsigned int u0 );
+int first_one01( unsigned int u0, unsigned int u1 );
+int first_one12( unsigned int u1, unsigned int u2 );
+int last_one01( unsigned int u0, unsigned int u1 );
+int last_one12( unsigned int u1, unsigned int u2 );
+int first_one1( unsigned int u1 );
+int first_one2( unsigned int u2 );
+int last_one0( unsigned int u0 );
+int last_one1( unsigned int u1 );
+int memory_free( void *p );
+int reset_time( unsigned int b_remain, unsigned int w_remain );
+int all_hash_learn_store( void );
+int gen_legal_moves( tree_t * restrict ptree, unsigned int *p0 );
+int rejections_probe( tree_t * restrict ptree, int turn, int ply );
+int ini( tree_t * restrict ptree );
+int fin( void );
+int ponder( tree_t * restrict ptree );
+int hash_learn( const tree_t * restrict ptree, unsigned int move, int value,
+ int depth );
+int book_on( void );
+int book_off( void );
+int hash_learn_on( void );
+int hash_learn_off( void );
+int is_move_check_b( const tree_t * restrict ptree, unsigned int move );
+int is_move_check_w( const tree_t * restrict ptree, unsigned int move );
+int solve_problems( tree_t * restrict ptree, unsigned int nposition );
+int read_board_rep1( const char *str_line, min_posi_t *pmin_posi );
+int com_turn_start( tree_t * restrict ptree, int flag );
+int read_record( tree_t * restrict ptree, const char *str_file,
+ unsigned int moves, int flag );
+int out_board( const tree_t * restrict ptree, FILE *pf, unsigned int move,
+ int flag );
+int make_root_move_list( tree_t * restrict ptree, int flag );
+int record_wind( record_t *pr );
+int book_probe( tree_t * restrict ptree );
+int detect_repetition( tree_t * restrict ptree, int ply, int turn, int nth );
+int is_mate( tree_t * restrict ptree, int ply );
+int is_mate_w_pawn_drop( tree_t * restrict ptree, int sq_drop );
+int is_mate_b_pawn_drop( tree_t * restrict ptree, int sq_drop );
+int clear_trans_table( void );
+int eval_max_score( const tree_t * restrict ptree, unsigned int move,
+ int stand_pat, int turn, int diff );
+int estimate_score_diff( const tree_t * restrict ptree, unsigned int move,
+ int turn );
+int eval_material( const tree_t * restrict ptree );
+int ini_trans_table( void );
+int is_hand_eq_supe( unsigned int u, unsigned int uref );
+int is_move_valid( tree_t * restrict ptree, unsigned int move, int turn );
+int is_hash_move_valid( tree_t * restrict ptree, unsigned int move, int turn );
+int iterate( tree_t * restrict ptree, int flag );
+int gen_next_move( tree_t * restrict ptree, int ply, int turn );
+int gen_next_evasion( tree_t * restrict ptree, int ply, int turn );
+int ini_game( tree_t * restrict ptree, const min_posi_t *pmin_posi, int flag,
+ const char *str_name1, const char *str_name2 );
+int open_history( const char *str_name1, const char *str_name2 );
+int next_cmdline( int is_wait );
+int procedure( tree_t * restrict ptree );
+int get_cputime( unsigned int *ptime );
+int get_elapsed( unsigned int *ptime );
+int interpret_CSA_move( tree_t * restrict ptree, unsigned int *pmove,
+ const char *str );
+int in_CSA( tree_t * restrict ptree, record_t *pr, unsigned int *pmove,
+ int do_history );
+int in_CSA_record( FILE * restrict pf, tree_t * restrict ptree );
+int renovate_time( int turn );
+int exam_tree( const tree_t * restrict ptree );
+int rep_check_root( tree_t * restrict ptree );
+int make_move_root( tree_t * restrict ptree, unsigned int move, int flag );
+int search_quies( tree_t * restrict ptree, int alpha, int beta, int turn,
+ int ply, int qui_ply );
+int search( tree_t * restrict ptree, int alpha, int beta, int turn,
+ int depth, int ply, unsigned int state_node );
+int searchr( tree_t * restrict ptree, int alpha, int beta, int turn,
+ int depth );
+int evaluate( tree_t * restrict ptree, int ply, int turn );
+int swap( const tree_t * restrict ptree, unsigned int move, int alpha,
+ int beta, int turn );
+int file_close( FILE *pf );
+int record_open( record_t *pr, const char *str_file,
+ record_mode_t record_mode, const char *str_name1,
+ const char *str_name2 );
+int record_close( record_t *pr );
+unsigned int phash( unsigned int move, int turn );
+unsigned int is_mate_in3ply( tree_t * restrict ptree, int turn, int ply );
+unsigned int is_b_mate_in_1ply( tree_t * restrict ptree );
+unsigned int is_w_mate_in_1ply( tree_t * restrict ptree );
+unsigned int hash_probe( tree_t * restrict ptree, int ply, int depth, int turn,
+ int alpha, int beta, unsigned int state_node );
+unsigned int rand32( void );
+unsigned int is_black_attacked( const tree_t * restrict ptree, int sq );
+unsigned int is_white_attacked( const tree_t * restrict ptree, int sq );
+unsigned int is_pinned_on_black_king( const tree_t * restrict ptree,
+ int isquare, int idirec );
+unsigned int is_pinned_on_white_king( const tree_t * restrict ptree,
+ int isquare, int idirec );
+unsigned int *b_gen_captures( const tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *b_gen_nocaptures( const tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *b_gen_drop( tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *b_gen_evasion( tree_t *restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *b_gen_checks( tree_t * restrict __ptree__,
+ unsigned int * restrict pmove );
+unsigned int *b_gen_cap_nopro_ex2( const tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *b_gen_nocap_nopro_ex2( const tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *w_gen_captures( const tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *w_gen_nocaptures( const tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *w_gen_drop( tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *w_gen_evasion( tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *w_gen_checks( tree_t * restrict __ptree__,
+ unsigned int * restrict pmove );
+unsigned int *w_gen_cap_nopro_ex2( const tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+unsigned int *w_gen_nocap_nopro_ex2( const tree_t * restrict ptree,
+ unsigned int * restrict pmove );
+uint64_t hash_func( const tree_t * restrict ptree );
+uint64_t rand64( void );
+trans_entry_t hash_learn_store( const tree_t * restrict ptree, int depth,
+ int value, unsigned int move );
+FILE *file_open( const char *str_file, const char *str_mode );
+bitboard_t attacks_to_piece( const tree_t * restrict ptree, int sq );
+bitboard_t horse_attacks( const tree_t * restrict ptree, int i );
+const char *str_time( unsigned int time );
+const char *str_time_symple( unsigned int time );
+const char *str_CSA_move( unsigned int move );
+const char *str_CSA_move_plus( tree_t * restrict ptree, unsigned int move,
+ int ply, int turn );
+
+#if defined(MPV)
+int root_mpv;
+int mpv_num;
+int mpv_width;
+pv_t mpv_pv[ MPV_MAX_PV*2 + 1 ];
+#endif
+
+#if defined(TLP)
+# define SignKey(word2, word1) word2 ^= ( word1 )
+# define TlpEnd() tlp_end();
+# if ! defined(_WIN32)
+extern pthread_attr_t pthread_attr;
+# endif
+# if defined(MNJ_LAN)
+uint64_t tlp_count_node( tree_t * restrict ptree );
+# endif
+void tlp_yield( void );
+void tlp_set_abort( tree_t * restrict ptree );
+void lock( lock_t *plock );
+void unlock( lock_t *plock );
+void tlp_end( void );
+int tlp_search( tree_t * restrict ptree, int alpha, int beta, int turn,
+ int depth, int ply, unsigned int state_node );
+int tlp_split( tree_t * restrict ptree );
+int tlp_start( void );
+int tlp_is_descendant( const tree_t * restrict ptree, int slot_ancestor );
+int lock_init( lock_t *plock );
+int lock_free( lock_t *plock );
+extern lock_t tlp_lock;
+extern volatile int tlp_abort;
+extern volatile int tlp_idle;
+extern volatile int tlp_num;
+extern int tlp_max;
+extern int tlp_nsplit;
+extern int tlp_nabort;
+extern int tlp_nslot;
+extern SHARE unsigned short tlp_rejections_slot[ REJEC_MASK+1 ];
+extern tree_t tlp_atree_work[ TLP_NUM_WORK ];
+extern tree_t * volatile tlp_ptrees[ TLP_MAX_THREADS ];
+#else /* no TLP */
+# define SignKey(word2, word1)
+# define TlpEnd()
+extern tree_t tree;
+#endif
+
+#if ! defined(_WIN32)
+extern clock_t clk_tck;
+#endif
+
+#if ! defined(NDEBUG)
+int exam_bb( const tree_t *ptree );
+#endif
+
+#if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
+# define Out( ... ) out( __VA_ARGS__ )
+void out( const char *format, ... );
+#else
+# define Out( ... )
+#endif
+
+#if ! defined(NO_LOGGING)
+extern FILE *pf_log;
+extern const char *str_dir_logs;
+#endif
+
+#if defined(NO_STDOUT) || defined(WIN32_PIPE)
+# define OutBeep()
+# define StdoutStress(x,y) 1
+# define StdoutNormal() 1
+#else
+# define OutBeep() out_beep()
+# define StdoutStress(x,y) stdout_stress(x,y)
+# define StdoutNormal() stdout_normal()
+void out_beep( void );
+int stdout_stress( int is_promote, int ifrom );
+int stdout_normal( void );
+#endif
+
+#if defined(CSA_LAN) && defined(MNJ_LAN)
+# define ShutdownClient sckt_shutdown( sckt_mnj ); \
+ sckt_shutdown( sckt_csa ); \
+ sckt_mnj = sckt_csa = SCKT_NULL
+#elif defined(CSA_LAN)
+# define ShutdownClient sckt_shutdown( sckt_csa ); \
+ sckt_csa = SCKT_NULL
+#elif defined(MNJ_LAN)
+# define ShutdownClient sckt_shutdown( sckt_mnj ); \
+ sckt_mnj = SCKT_NULL
+#else
+# define ShutdownClient
+#endif
+
+#if defined(CSA_LAN) || defined(MNJ_LAN)
+int client_next_game( tree_t * restrict ptree, const char *str_addr,
+ int iport );
+sckt_t sckt_connect( const char *str_addr, int iport );
+int sckt_shutdown( sckt_t sd );
+int sckt_check( sckt_t sd );
+int sckt_in( sckt_t sd, char *str, int n );
+int sckt_out( sckt_t sd, const char *fmt, ... );
+extern unsigned int time_last_send;
+#endif
+
+#if defined(CSA_LAN)
+extern int client_turn;
+extern int client_ngame;
+extern int client_max_game;
+extern long client_port;
+extern char client_str_addr[256];
+extern char client_str_id[256];
+extern char client_str_pwd[256];
+extern sckt_t sckt_csa;
+#endif
+
+#if defined(MNJ_LAN)
+# define MnjOut( ... ) if ( sckt_mnj != SCKT_NULL ) \
+ sckt_out( sckt_mnj, __VA_ARGS__ )
+extern short mnj_tbl[ MNJ_MASK + 1 ];
+extern sckt_t sckt_mnj;
+int mnj_reset_tbl( int sd, unsigned int seed );
+int analyze( tree_t * restrict ptree );
+int mnj_posi_id;
+unsigned int mnj_move_last;
+#else
+# define MnjOut( ... )
+#endif
+
+
+#if defined(DEKUNOBOU) || defined(CSA_LAN) || defined(MNJ_LAN)
+const char *str_WSAError( const char *str );
+#endif
+
+#if defined(DEKUNOBOU) && defined(_WIN32)
+# define OutDek( ... ) if ( dek_ngame ) { int i = dek_out( __VA_ARGS__ ); \
+ if ( i < 0 ) { return i; } }
+const char *str_WSAError( const char *str );
+int dek_start( const char *str_sddr, int port_dek, int port_bnz );
+int dek_next_game( tree_t * restrict ptree );
+int dek_in( char *str, int n );
+int dek_out( const char *format, ... );
+int dek_parse( char *str, int len );
+int dek_check( void );
+extern SOCKET dek_socket_in;
+extern SOCKET dek_s_accept;
+extern u_long dek_ul_addr;
+extern unsigned int dek_ngame;
+extern unsigned int dek_lost;
+extern unsigned int dek_win;
+extern int dek_turn;
+extern u_short dek_ns;
+#else
+# define OutDek( ... )
+#endif
+
+#if defined(CSASHOGI)
+# define OutCsaShogi( ... ) out_csashogi( __VA_ARGS__ )
+void out_csashogi( const char *format, ... );
+#else
+# define OutCsaShogi( ... )
+#endif
+
+#define AttackBishop(bb,i) BBOr( bb, AttackDiag1(i), AttackDiag2(i) )
+#define AttackRook(bb,i) (bb) = AttackFile(i); \
+ (bb).p[aslide[i].ir0] |= AttackRank(i)
+
+
+
+extern check_table_t b_chk_tbl[nsquare];
+extern check_table_t w_chk_tbl[nsquare];
+
+#if defined(DBG_EASY)
+extern unsigned int easy_move;
+#endif
+
+#if defined(MINIMUM)
+
+# define MT_CAP_PAWN ( DPawn + DPawn )
+# define MT_CAP_LANCE ( DLance + DLance )
+# define MT_CAP_KNIGHT ( DKnight + DKnight )
+# define MT_CAP_SILVER ( DSilver + DSilver )
+# define MT_CAP_GOLD ( DGold + DGold )
+# define MT_CAP_BISHOP ( DBishop + DBishop )
+# define MT_CAP_ROOK ( DRook + DRook )
+# define MT_CAP_PRO_PAWN ( DProPawn + DPawn )
+# define MT_CAP_PRO_LANCE ( DProLance + DLance )
+# define MT_CAP_PRO_KNIGHT ( DProKnight + DKnight )
+# define MT_CAP_PRO_SILVER ( DProSilver + DSilver )
+# define MT_CAP_HORSE ( DHorse + DBishop )
+# define MT_CAP_DRAGON ( DDragon + DRook )
+# define MT_CAP_KING ( DKing + DKing )
+# define MT_PRO_PAWN ( DProPawn - DPawn )
+# define MT_PRO_LANCE ( DProLance - DLance )
+# define MT_PRO_KNIGHT ( DProKnight - DKnight )
+# define MT_PRO_SILVER ( DProSilver - DSilver )
+# define MT_PRO_BISHOP ( DHorse - DBishop )
+# define MT_PRO_ROOK ( DDragon - DRook )
+
+#else
+
+# define MT_CAP_PAWN ( p_value_ex[ 15 + pawn ] )
+# define MT_CAP_LANCE ( p_value_ex[ 15 + lance ] )
+# define MT_CAP_KNIGHT ( p_value_ex[ 15 + knight ] )
+# define MT_CAP_SILVER ( p_value_ex[ 15 + silver ] )
+# define MT_CAP_GOLD ( p_value_ex[ 15 + gold ] )
+# define MT_CAP_BISHOP ( p_value_ex[ 15 + bishop ] )
+# define MT_CAP_ROOK ( p_value_ex[ 15 + rook ] )
+# define MT_CAP_PRO_PAWN ( p_value_ex[ 15 + pro_pawn ] )
+# define MT_CAP_PRO_LANCE ( p_value_ex[ 15 + pro_lance ] )
+# define MT_CAP_PRO_KNIGHT ( p_value_ex[ 15 + pro_knight ] )
+# define MT_CAP_PRO_SILVER ( p_value_ex[ 15 + pro_silver ] )
+# define MT_CAP_HORSE ( p_value_ex[ 15 + horse ] )
+# define MT_CAP_DRAGON ( p_value_ex[ 15 + dragon ] )
+# define MT_CAP_KING ( DKing + DKing )
+# define MT_PRO_PAWN ( benefit2promo[ 7 + pawn ] )
+# define MT_PRO_LANCE ( benefit2promo[ 7 + lance ] )
+# define MT_PRO_KNIGHT ( benefit2promo[ 7 + knight ] )
+# define MT_PRO_SILVER ( benefit2promo[ 7 + silver ] )
+# define MT_PRO_BISHOP ( benefit2promo[ 7 + bishop ] )
+# define MT_PRO_ROOK ( benefit2promo[ 7 + rook ] )
+
+void fill_param_zero( void );
+void ini_param( param_t *p );
+void add_param( param_t *p1, const param_t *p2 );
+void inc_param( const tree_t * restrict ptree, param_t * restrict pd,
+ double dinc );
+void param_sym( param_t *p );
+void renovate_param( const param_t *pd );
+int learn( tree_t * restrict ptree, int is_ini, int nsteps,
+ unsigned int max_games, int max_iterations,
+ int nworker1, int nworker2 );
+int record_setpos( record_t *pr, const rpos_t *prpos );
+int record_getpos( record_t *pr, rpos_t *prpos );
+int record_rewind( record_t *pr );
+int book_create( tree_t * restrict ptree );
+int hash_learn_create( void );
+int out_param( void );
+double calc_penalty( void );
+
+#endif /* no MINIMUM */
+
+#if ( REP_HIST_LEN - PLY_MAX ) < 1
+# error "REP_HIST_LEN - PLY_MAX is too small."
+#endif
+
+#if defined(CSA_LAN) && '\n' != 0x0a
+# error "'\n' is not the ASCII code of LF (0x0a)."
+#endif
+
+#endif /* SHOGI_H */
--- /dev/null
+#include <stdlib.h>
+#include <limits.h>
+#include "shogi.h"
+
+int
+swap( const tree_t * restrict ptree, unsigned int move, int root_alpha,
+ int root_beta, int turn )
+{
+ bitboard_t bb, bb_temp, bb_attack;
+ unsigned int uattack;
+ int attacked_piece, from, to, nc, ir0;
+ int piece_cap, piece, value, xvalue, alpha, beta, is_promo;
+
+ from = (int)I2From( move );
+ to = (int)I2To( move );
+
+ if ( from >= nsquare )
+ {
+ value = 0;
+ piece = From2Drop( from );
+ attacked_piece = p_value_ex[15+piece];
+ }
+ else {
+ piece = (int)I2PieceMove( move );
+ piece_cap = (int)UToCap( move );
+ is_promo = (int)I2IsPromote( move );
+
+ value = p_value_ex[15+piece_cap];
+ attacked_piece = p_value_ex[15+piece];
+ if ( is_promo )
+ {
+ value += benefit2promo[7+piece];
+ attacked_piece += benefit2promo[7+piece];
+ }
+ xvalue = value - attacked_piece - MT_PRO_PAWN;
+ if ( xvalue >= root_beta ) { return xvalue; }
+ }
+
+ bb_attack = attacks_to_piece( ptree, to );
+ alpha = INT_MIN;
+ beta = value;
+ for ( nc = 1;; nc++ )
+ {
+ /* remove an attacker, and add a hidden piece to attack bitmap */
+ if ( from < nsquare )
+ {
+ Xor( from, bb_attack );
+ switch ( adirec[to][from] )
+ {
+ case direc_rank:
+ ir0 = aslide[from].ir0;
+ uattack = AttackRank( from );
+ if ( from > to ) { uattack &= abb_plus_rays[from].p[ir0]; }
+ else { uattack &= abb_minus_rays[from].p[ir0]; }
+ uattack &= BB_B_RD.p[ir0] | BB_W_RD.p[ir0];
+ bb_attack.p[ir0] |= uattack;
+ break;
+
+ case direc_file:
+ bb = AttackFile( from );
+ BBOr( bb_temp, BB_B_RD, BB_W_RD );
+ if ( from > to )
+ {
+ BBOr( bb_temp, bb_temp, BB_BLANCE );
+ BBAnd( bb, bb, abb_plus_rays[from] );
+ }
+ else {
+ BBOr( bb_temp, bb_temp, BB_WLANCE );
+ BBAnd( bb, bb, abb_minus_rays[from] );
+ }
+ BBAnd( bb, bb, bb_temp );
+ BBOr( bb_attack, bb_attack, bb );
+ break;
+
+ case direc_diag1:
+ bb = AttackDiag1( from );
+ if ( from > to ) { BBAnd( bb, bb, abb_plus_rays[from] ); }
+ else { BBAnd( bb, bb, abb_minus_rays[from] ); }
+ BBOr( bb_temp, BB_B_BH, BB_W_BH );
+ BBAnd( bb, bb, bb_temp );
+ BBOr( bb_attack, bb_attack, bb );
+ break;
+
+ case direc_diag2:
+ bb = AttackDiag2( from );
+ if ( from > to ) { BBAnd( bb, bb, abb_plus_rays[from] ); }
+ else { BBAnd( bb, bb, abb_minus_rays[from] ); }
+ BBOr( bb_temp, BB_B_BH, BB_W_BH );
+ BBAnd( bb, bb, bb_temp );
+ BBOr( bb_attack, bb_attack, bb );
+ break;
+
+ }
+ }
+ if ( ! BBToU( bb_attack ) ) { break; }
+
+ /* find a cheapest piece attacking the target */
+ turn = Flip( turn );
+ value = attacked_piece - value;
+ if ( turn )
+ {
+ if( BBContract( bb_attack, BB_WPAWN ) )
+ {
+ from = to-nfile;
+ attacked_piece = MT_CAP_PAWN;
+ if ( to > 53 )
+ {
+ value += MT_PRO_PAWN;
+ attacked_piece += MT_PRO_PAWN;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WLANCE, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_LANCE;
+ if ( to > 53 )
+ {
+ value += MT_PRO_LANCE;
+ attacked_piece += MT_PRO_LANCE;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WKNIGHT, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_KNIGHT;
+ if ( to > 53 )
+ {
+ value += MT_PRO_KNIGHT;
+ attacked_piece += MT_PRO_KNIGHT;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WPRO_PAWN, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_PRO_PAWN;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WPRO_LANCE, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_PRO_LANCE;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WPRO_KNIGHT, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_PRO_KNIGHT;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WSILVER, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_SILVER;
+ if ( from > 53 || to > 53 )
+ {
+ value += MT_PRO_SILVER;
+ attacked_piece += MT_PRO_SILVER;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WPRO_SILVER, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_PRO_SILVER;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WGOLD, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_GOLD;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WBISHOP, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_BISHOP;
+ if ( from > 53 || to > 53 )
+ {
+ value += MT_PRO_BISHOP;
+ attacked_piece += MT_PRO_BISHOP;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WHORSE, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_HORSE;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WROOK, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_ROOK;
+ if ( from > 53 || to > 53 )
+ {
+ value += MT_PRO_ROOK;
+ attacked_piece += MT_PRO_ROOK;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_WDRAGON, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_DRAGON;
+ goto ab_cut;
+ }
+ if( BBContract( bb_attack, BB_WKING ) )
+ {
+ from = SQ_WKING;
+ attacked_piece = MT_CAP_KING;
+ goto ab_cut;
+ }
+ }
+ else {
+ if( BBContract( bb_attack, BB_BPAWN ) )
+ {
+ from = to+nfile;
+ attacked_piece = MT_CAP_PAWN;
+ if ( to < 27 )
+ {
+ value += MT_PRO_PAWN;
+ attacked_piece += MT_PRO_PAWN;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BLANCE, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_LANCE;
+ if ( to < 27 )
+ {
+ value += MT_PRO_LANCE;
+ attacked_piece += MT_PRO_LANCE;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BKNIGHT, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_KNIGHT;
+ if ( to < 27 )
+ {
+ value += MT_PRO_KNIGHT;
+ attacked_piece += MT_PRO_KNIGHT;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BPRO_PAWN, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_PRO_PAWN;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BPRO_LANCE, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_PRO_LANCE;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BPRO_KNIGHT, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_PRO_KNIGHT;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BSILVER, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_SILVER;
+ if ( from < 27 || to < 27 )
+ {
+ value += MT_PRO_SILVER;
+ attacked_piece += MT_PRO_SILVER;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BPRO_SILVER, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_PRO_SILVER;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BGOLD, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_GOLD;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BBISHOP, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_BISHOP;
+ if ( from < 27 || to < 27 )
+ {
+ value += MT_PRO_BISHOP;
+ attacked_piece += MT_PRO_BISHOP;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BHORSE, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_HORSE;
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BROOK, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_ROOK;
+ if ( from < 27 || to < 27 )
+ {
+ value += MT_PRO_ROOK;
+ attacked_piece += MT_PRO_ROOK;
+ }
+ goto ab_cut;
+ }
+ BBAnd( bb, BB_BDRAGON, bb_attack );
+ if( BBToU( bb ) )
+ {
+ from = FirstOne( bb );
+ attacked_piece = MT_CAP_DRAGON;
+ goto ab_cut;
+ }
+ if( BBContract( bb_attack, BB_BKING ) )
+ {
+ from = SQ_BKING;
+ attacked_piece = MT_CAP_KING;
+ goto ab_cut;
+ }
+ }
+ break;
+
+ ab_cut:
+ if ( nc & 1 )
+ {
+ if ( -value > alpha )
+ {
+ if ( -value >= beta ) { return beta; }
+ if ( -value >= root_beta ) { return -value; }
+ alpha = -value;
+ }
+ else {
+ xvalue = attacked_piece + MT_PRO_PAWN - value;
+ if ( xvalue <= alpha ) { return alpha; }
+ if ( xvalue <= root_alpha ) { return xvalue; }
+ }
+ }
+ else {
+ if ( value < beta )
+ {
+ if ( value <= alpha ) { return alpha; }
+ if ( value <= root_alpha ) { return value; }
+ beta = value;
+ }
+ else {
+ xvalue = value - attacked_piece - MT_PRO_PAWN;
+ if ( xvalue >= beta ) { return beta; }
+ if ( xvalue >= root_beta ) { return xvalue; }
+ }
+ }
+ }
+
+ if ( nc & 1 ) { return beta; }
+ else { return alpha; }
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_WIN32)
+# include <process.h>
+#else
+# include <sched.h>
+#endif
+#include "shogi.h"
+
+#if defined(TLP)
+
+# if defined(_WIN32)
+static unsigned int __stdcall start_address( void *arg );
+# else
+static void *start_address( void *arg );
+# endif
+
+static tree_t *find_child( void );
+static void init_state( const tree_t * restrict parent,
+ tree_t * restrict child );
+static void copy_state( tree_t * restrict parent,
+ const tree_t * restrict child, int value );
+static void wait_work( int tid, tree_t *parent );
+
+int
+tlp_start( void )
+{
+ int work[ TLP_MAX_THREADS ];
+ int num;
+
+ if ( tlp_num ) { return 1; }
+
+ for ( num = 1; num < tlp_max; num++ )
+ {
+ work[num] = num;
+
+# if defined(_WIN32)
+ if ( ! _beginthreadex( 0, 0, start_address, work+num, 0, 0 ) )
+ {
+ str_error = "_beginthreadex() failed.";
+ return -2;
+ }
+# else
+ {
+ pthread_t pt;
+ if ( pthread_create( &pt, &pthread_attr, start_address, work+num ) )
+ {
+ str_error = "pthread_create() failed.";
+ return -2;
+ }
+ }
+# endif
+ }
+ while ( tlp_num +1 < tlp_max ) { tlp_yield(); }
+
+ return 1;
+}
+
+
+void
+tlp_end( void )
+{
+ tlp_abort = 1;
+ while ( tlp_num ) { tlp_yield(); }
+ tlp_abort = 0;
+}
+
+
+int
+tlp_split( tree_t * restrict ptree )
+{
+ tree_t *child;
+ int num, nchild, i;
+
+ lock( &tlp_lock );
+
+ if ( ! tlp_idle || ptree->tlp_abort )
+ {
+ unlock( &tlp_lock );
+ return 0;
+ }
+
+ tlp_ptrees[ ptree->tlp_id ] = NULL;
+ ptree->tlp_nsibling = 0;
+ nchild = 0;
+ for ( num = 0; num < tlp_max; num++ )
+ {
+ if ( tlp_ptrees[num] ) { ptree->tlp_ptrees_sibling[num] = 0; }
+ else {
+ child = find_child();
+ if ( ! child ) { continue; }
+
+ nchild += 1;
+
+ for ( i=0; i<tlp_max; i++ ) { child->tlp_ptrees_sibling[i] = NULL; }
+ child->tlp_ptree_parent = ptree;
+ child->tlp_id = (unsigned char)num;
+ child->tlp_used = 1;
+ child->tlp_abort = 0;
+ ptree->tlp_ptrees_sibling[num] = child;
+ ptree->tlp_nsibling += 1;
+ init_state( ptree, child );
+
+ tlp_ptrees[num] = child;
+ }
+ }
+
+ if ( ! nchild )
+ {
+ tlp_ptrees[ ptree->tlp_id ] = ptree;
+ unlock( &tlp_lock );
+ return 0;
+ }
+
+ tlp_nsplit += 1;
+ tlp_idle += 1;
+
+ unlock( &tlp_lock );
+
+ wait_work( ptree->tlp_id, ptree );
+
+ return 1;
+}
+
+
+void
+tlp_set_abort( tree_t * restrict ptree )
+{
+ int num;
+
+ ptree->tlp_abort = 1;
+ for ( num = 0; num < tlp_max; num++ )
+ if ( ptree->tlp_ptrees_sibling[num] )
+ {
+ tlp_set_abort( ptree->tlp_ptrees_sibling[num] );
+ }
+}
+
+
+#if defined(MNJ_LAN)
+uint64_t
+tlp_count_node( tree_t * restrict ptree )
+{
+ uint64_t uret = ptree->node_searched;
+ int num;
+
+ for ( num = 0; num < tlp_max; num++ )
+ if ( ptree->tlp_ptrees_sibling[num] )
+ {
+ uret += tlp_count_node( ptree->tlp_ptrees_sibling[num] );
+ }
+
+ return uret;
+}
+#endif
+
+
+int
+tlp_is_descendant( const tree_t * restrict ptree, int slot_ancestor )
+{
+ int slot = (int)ptree->tlp_slot;
+
+ for ( ;; ) {
+ if ( slot == slot_ancestor ) { return 1; }
+ else if ( ! slot ) { return 0; }
+ else { slot = tlp_atree_work[slot].tlp_ptree_parent->tlp_slot; }
+ }
+}
+
+
+int
+lock_init( lock_t *plock )
+{
+# if defined(_MSC_VER)
+ *plock = 0;
+# elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+ *plock = 0;
+# else
+ if ( pthread_mutex_init( plock, 0 ) )
+ {
+ str_error = "pthread_mutex_init() failed.";
+ return -1;
+ }
+# endif
+ return 1;
+}
+
+
+int
+lock_free( lock_t *plock )
+{
+# if defined(_MSC_VER)
+ *plock = 0;
+# elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+ *plock = 0;
+# else
+ if ( pthread_mutex_destroy( plock ) )
+ {
+ str_error = "pthread_mutex_destroy() failed.";
+ return -1;
+ }
+# endif
+ return 1;
+}
+
+
+void
+unlock( lock_t *plock )
+{
+# if defined(_MSC_VER)
+ *plock = 0;
+# elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+ *plock = 0;
+# else
+ pthread_mutex_unlock( plock );
+# endif
+}
+
+
+void
+lock( lock_t *plock )
+{
+# if defined(_MSC_VER)
+ long l;
+
+ for ( ;; )
+ {
+ l = _InterlockedExchange( (void *)plock, 1 );
+ if ( ! l ) { return; }
+ while ( *plock );
+ }
+# elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+ int itemp;
+
+ for ( ;; )
+ {
+ asm ( "1: movl $1, %1 \n\t"
+ " xchgl (%0), %1 \n\t"
+ : "=g" (plock), "=r" (itemp) : "0" (plock) );
+ if ( ! itemp ) { return; }
+ while ( *plock );
+ }
+# else
+ pthread_mutex_lock( plock );
+# endif
+}
+
+
+void
+tlp_yield( void )
+{
+#if defined(_WIN32)
+ Sleep( 0 );
+#else
+ sched_yield();
+#endif
+}
+
+
+# if defined(_MSC_VER)
+static unsigned int __stdcall start_address( void *arg )
+# else
+static void *start_address( void *arg )
+#endif
+{
+ int tid = *(int *)arg;
+
+ tlp_ptrees[tid] = NULL;
+
+ lock( &tlp_lock );
+ Out( "Hi from thread no.%d\n", tid );
+ tlp_num += 1;
+ tlp_idle += 1;
+ unlock( &tlp_lock );
+
+ wait_work( tid, NULL );
+
+ lock( &tlp_lock );
+ Out( "Bye from thread no.%d\n", tid );
+ tlp_num -= 1;
+ tlp_idle -= 1;
+ unlock( &tlp_lock );
+
+ return 0;
+}
+
+
+static void
+wait_work( int tid, tree_t *parent )
+{
+ tree_t *slot;
+ int value;
+
+ for ( ;; ) {
+
+ for ( ;; ) {
+ if ( tlp_ptrees[tid] ) { break; }
+ if ( parent && ! parent->tlp_nsibling ) { break; }
+ if ( tlp_abort ) { return; }
+
+ tlp_yield();
+ }
+
+ lock( &tlp_lock );
+ if ( ! tlp_ptrees[tid] ) { tlp_ptrees[tid] = parent; }
+ tlp_idle -= 1;
+ unlock( &tlp_lock );
+
+ slot = tlp_ptrees[tid];
+ if ( slot == parent ) { return; }
+
+ value = tlp_search( slot,
+ slot->tlp_ptree_parent->tlp_best,
+ slot->tlp_ptree_parent->tlp_beta,
+ slot->tlp_ptree_parent->tlp_turn,
+ slot->tlp_ptree_parent->tlp_depth,
+ slot->tlp_ptree_parent->tlp_ply,
+ slot->tlp_ptree_parent->tlp_state_node );
+
+ lock( &tlp_lock );
+ copy_state( slot->tlp_ptree_parent, slot, value );
+ slot->tlp_ptree_parent->tlp_nsibling -= 1;
+ slot->tlp_ptree_parent->tlp_ptrees_sibling[tid] = NULL;
+ slot->tlp_used = 0;
+ tlp_ptrees[tid] = NULL;
+ tlp_idle += 1;
+ unlock( &tlp_lock);
+ }
+}
+
+
+static tree_t *
+find_child( void )
+{
+ int i;
+
+ for ( i = 1; i < TLP_NUM_WORK && tlp_atree_work[i].tlp_used; i++ );
+ if ( i == TLP_NUM_WORK ) { return NULL; }
+ if ( i > tlp_nslot ) { tlp_nslot = i; }
+
+ return tlp_atree_work + i;
+}
+
+
+static void
+init_state( const tree_t * restrict parent, tree_t * restrict child )
+{
+ int i, ply;
+
+ child->posi = parent->posi;
+ child->node_searched = 0;
+ child->null_pruning_done = 0;
+ child->null_pruning_tried = 0;
+ child->check_extension_done = 0;
+ child->recap_extension_done = 0;
+ child->onerp_extension_done = 0;
+ child->neval_called = 0;
+ child->nquies_called = 0;
+ child->nfour_fold_rep = 0;
+ child->nperpetual_check = 0;
+ child->nsuperior_rep = 0;
+ child->nrep_tried = 0;
+ child->nreject_tried = 0;
+ child->nreject_done = 0;
+ child->ntrans_always_hit = 0;
+ child->ntrans_prefer_hit = 0;
+ child->ntrans_probe = 0;
+ child->ntrans_exact = 0;
+ child->ntrans_lower = 0;
+ child->ntrans_upper = 0;
+ child->ntrans_superior_hit = 0;
+ child->ntrans_inferior_hit = 0;
+ child->fail_high = 0;
+ child->fail_high_first = 0;
+ ply = parent->tlp_ply;
+
+ child->anext_move[ply].value_cap1 = parent->anext_move[ply].value_cap1;
+ child->anext_move[ply].value_cap2 = parent->anext_move[ply].value_cap2;
+ child->anext_move[ply].move_cap1 = parent->anext_move[ply].move_cap1;
+ child->anext_move[ply].move_cap2 = parent->anext_move[ply].move_cap2;
+
+ child->move_last[ply] = child->amove;
+ child->stand_pat[ply] = parent->stand_pat[ply];
+ child->current_move[ply-1] = parent->current_move[ply-1];
+ child->nsuc_check[ply-1] = parent->nsuc_check[ply-1];
+ child->nsuc_check[ply] = parent->nsuc_check[ply];
+
+ memcpy( child->hist_good, parent->hist_good, sizeof(parent->hist_good) );
+ memcpy( child->hist_tried, parent->hist_tried, sizeof(parent->hist_tried) );
+
+ for ( i = 0; i < root_nrep + ply - 1; i++ )
+ {
+ child->rep_board_list[i] = parent->rep_board_list[i];
+ child->rep_hand_list[i] = parent->rep_hand_list[i];
+ }
+ for ( i = ply; i < PLY_MAX; i++ )
+ {
+ child->amove_killer[i] = parent->amove_killer[i];
+ child->killers[i] = parent->killers[i];
+ }
+
+}
+
+
+static void
+copy_state( tree_t * restrict parent, const tree_t * restrict child,
+ int value )
+{
+ int i, ply;
+
+ parent->check_extension_done += child->check_extension_done;
+ parent->recap_extension_done += child->recap_extension_done;
+
+ if ( ! child->node_searched ) { return; }
+
+ parent->node_searched += child->node_searched;
+ parent->null_pruning_done += child->null_pruning_done;
+ parent->null_pruning_tried += child->null_pruning_tried;
+ parent->onerp_extension_done += child->onerp_extension_done;
+ parent->neval_called += child->neval_called;
+ parent->nquies_called += child->nquies_called;
+ parent->nrep_tried += child->nrep_tried;
+ parent->nfour_fold_rep += child->nfour_fold_rep;
+ parent->nperpetual_check += child->nperpetual_check;
+ parent->nsuperior_rep += child->nsuperior_rep;
+ parent->nreject_tried += child->nreject_tried;
+ parent->nreject_done += child->nreject_done;
+ parent->ntrans_always_hit += child->ntrans_always_hit;
+ parent->ntrans_prefer_hit += child->ntrans_prefer_hit;
+ parent->ntrans_probe += child->ntrans_probe;
+ parent->ntrans_exact += child->ntrans_exact;
+ parent->ntrans_lower += child->ntrans_lower;
+ parent->ntrans_upper += child->ntrans_upper;
+ parent->ntrans_superior_hit += child->ntrans_superior_hit;
+ parent->ntrans_inferior_hit += child->ntrans_inferior_hit;
+ parent->fail_high_first += child->fail_high_first;
+ parent->fail_high += child->fail_high;
+
+ if ( child->tlp_abort || value <= parent->tlp_best ) { return; }
+
+ ply = parent->tlp_ply;
+ parent->tlp_best = (short)value;
+ parent->pv[ply] = child->pv[ply];
+ parent->current_move[ply] = child->current_move[ply];
+
+ memcpy( parent->hist_tried, child->hist_tried, sizeof(child->hist_tried) );
+ memcpy( parent->hist_good, child->hist_good, sizeof(child->hist_good) );
+
+ for ( i = ply; i < PLY_MAX; i++ )
+ {
+ parent->amove_killer[i] = child->amove_killer[i];
+ parent->killers[i] = child->killers[i];
+ }
+}
+
+
+#endif /* TLP */
--- /dev/null
+#include <limits.h>
+#include <assert.h>
+#if ! defined(_WIN32)
+# include <sys/time.h>
+# include <time.h>
+#endif
+#include "shogi.h"
+
+
+void
+set_search_limit_time( int turn )
+/*
+ [inputs]
+ global variables:
+ sec_limit time limit of a side for an entire game in seconds
+ sec_limit_up time limit for a move when the ordinary time has run out.
+ the time is known as 'byo-yomi'.
+ sec_b_total seconds spent by black
+ sec_w_total seconds spent by white
+ time_response
+ ( game_status & flag_puzzling ) time-control for puzzling-search
+ ( game_status & flag_pondering ) time-control for pondering-search
+ ( game_status & flag_time_extendable ) bonanza isn't punctual to the time
+
+ argument:
+ turn a side to move
+
+ [outputs]
+ global variables:
+ time_limit tentative deadline for searching in millisecond
+ time_max_limit maximum allowed time to search in millisecond
+
+ [working area]
+ local variables:
+ sec_elapsed second spent by the side to move
+ sec_left time left for the side in seconds
+ u0 tentative deadline for searching in second
+ u1 maximum allowed time to search in second
+*/
+{
+ unsigned int u0, u1;
+
+ /* no time-control */
+ if ( sec_limit_up == UINT_MAX || ( game_status & flag_pondering ) )
+ {
+ time_max_limit = time_limit = UINT_MAX;
+ return;
+ }
+
+ /* not punctual to the time */
+ if ( ! sec_limit && ( game_status & flag_time_extendable ) )
+ {
+ u0 = sec_limit_up;
+ u1 = sec_limit_up * 5U;
+ }
+ /* have byo-yomi */
+ else if ( sec_limit_up )
+ {
+ unsigned int umax, umin, sec_elapsed, sec_left;
+
+ sec_elapsed = turn ? sec_w_total : sec_b_total;
+ sec_left = ( sec_elapsed <= sec_limit ) ? sec_limit - sec_elapsed : 0;
+ u0 = ( sec_left + ( TC_NMOVE / 2U ) ) / TC_NMOVE;
+
+ /*
+ t = 2s is not beneficial since 2.8s are almost the same as 1.8s.
+ So that, we rather want to use up the ordinary time.
+ */
+ if ( u0 == 2U ) { u0 = 3U; }
+
+ /* 'byo-yomi' is so long that the ordinary time-limit is negligible. */
+ if ( u0 < sec_limit_up * 3U / 2U ) { u0 = sec_limit_up * 3U / 2U; }
+
+ u1 = u0 * 5U;
+
+ umax = sec_left + sec_limit_up;
+ umin = 1;
+
+ if ( umax < u0 ) { u0 = umax; }
+ if ( umax < u1 ) { u1 = umax; }
+ if ( umin > u0 ) { u0 = umin; }
+ if ( umin > u1 ) { u1 = umin; }
+ }
+ /* no byo-yomi */
+ else {
+ unsigned int sec_elapsed, sec_left;
+
+ sec_elapsed = turn ? sec_w_total : sec_b_total;
+
+ /* We have some seconds left to think. */
+ if ( sec_elapsed + SEC_MARGIN < sec_limit )
+ {
+ sec_left = sec_limit - sec_elapsed;
+ u0 = ( sec_left + ( TC_NMOVE / 2U ) ) / TC_NMOVE;
+
+ /* t = 2s is not beneficial since 2.8s is almost the same as 1.8s. */
+ /* So that, we rather want to save the time. */
+ if ( u0 == 2U ) { u0 = 1U; }
+ u1 = u0 * 5U;
+ }
+ /* We are running out of time... */
+ else { u0 = u1 = 1U; }
+ }
+
+ time_limit = u0 * 1000U + 1000U - time_response;
+ time_max_limit = u1 * 1000U + 1000U - time_response;
+
+ if ( game_status & flag_puzzling )
+ {
+ time_max_limit = time_max_limit / 5U;
+ time_limit = time_max_limit / 5U;
+ }
+
+ Out( "- time ctrl: %u -- %u\n", time_limit, time_max_limit );
+}
+
+
+int
+renovate_time( int turn )
+{
+ unsigned int te, time_elapsed;
+ int iret;
+
+ iret = get_elapsed( &te );
+ if ( iret < 0 ) { return iret; }
+
+ time_elapsed = te - time_turn_start;
+ sec_elapsed = time_elapsed / 1000U;
+ if ( ! sec_elapsed ) { sec_elapsed = 1U; }
+
+ if ( turn ) { sec_w_total += sec_elapsed; }
+ else { sec_b_total += sec_elapsed; }
+
+ time_turn_start = te;
+
+ return 1;
+}
+
+
+void
+adjust_time( unsigned int elapsed_new, int turn )
+{
+ const char *str = "TIME SKEW DETECTED";
+
+ if ( turn )
+ {
+ if ( sec_w_total + elapsed_new < sec_elapsed )
+ {
+ out_warning( str );
+ sec_w_total = 0;
+ }
+ else { sec_w_total = sec_w_total + elapsed_new - sec_elapsed; };
+ }
+ else {
+ if ( sec_b_total + elapsed_new < sec_elapsed )
+ {
+ out_warning( str );
+ sec_b_total = 0;
+ }
+ else { sec_b_total = sec_b_total + elapsed_new - sec_elapsed; };
+ }
+}
+
+
+int
+reset_time( unsigned int b_remain, unsigned int w_remain )
+{
+ if ( sec_limit_up == UINT_MAX )
+ {
+ str_error = "no time limit is set";
+ return -2;
+ }
+
+ if ( b_remain > sec_limit || w_remain > sec_limit )
+ {
+ snprintf( str_message, SIZE_MESSAGE,
+ "time remaining can't be larger than %u", sec_limit );
+ str_error = str_message;
+ return -2;
+ }
+
+ sec_b_total = sec_limit - b_remain;
+ sec_w_total = sec_limit - w_remain;
+ Out( " elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
+
+ return 1;
+}
+
+
+const char *
+str_time( unsigned int time )
+{
+ static char str[32];
+ unsigned int time_min = time / 60000;
+ unsigned int time_sec = time / 1000;
+ unsigned int time_mil = time % 1000;
+
+ if ( time_min < 60 )
+ {
+ snprintf( str, 32, "%02u:%02u.%02u",
+ time_min, time_sec%60, time_mil/10 );
+ }
+ else {
+ snprintf( str, 32, "%02u:%02u:%02u.%02u",
+ time_min / 60, time_min % 60, time_sec%60, time_mil/10 );
+ }
+ return str;
+}
+
+
+const char *
+str_time_symple( unsigned int time )
+{
+ static char str[32];
+ unsigned int time_min = time / 60000;
+ unsigned int time_sec = time / 1000;
+ unsigned int time_mil = time % 1000;
+
+ if ( time_min == 0 )
+ {
+ snprintf( str, 32, "%5.2f", (float)(time_sec*1000+time_mil)/1000.0 );
+ }
+ else { snprintf( str, 32, "%2u:%02u", time_min, time_sec % 60 ); }
+
+ return str;
+}
+
+
+int
+get_cputime( unsigned int *ptime )
+{
+#if defined(_WIN32)
+ HANDLE hProcess;
+ FILETIME CreationTime, ExitTime, KernelTime, UserTime;
+ ULARGE_INTEGER uli_temp;
+
+ hProcess = GetCurrentProcess();
+ if ( GetProcessTimes( hProcess, &CreationTime, &ExitTime,
+ &KernelTime, &UserTime ) )
+ {
+ uli_temp.LowPart = UserTime.dwLowDateTime;
+ uli_temp.HighPart = UserTime.dwHighDateTime;
+ *ptime = (unsigned int)( uli_temp.QuadPart / 10000 );
+ }
+ else {
+# if 0 /* winnt */
+ str_error = "GetProcessTimes() failed.";
+ return -1;
+# else /* win95 */
+ *ptime = 0U;
+# endif
+ }
+#else
+ clock_t clock_temp;
+ struct tms t;
+
+ if ( times( &t ) == -1 )
+ {
+ str_error = "times() faild.";
+ return -1;
+ }
+ clock_temp = t.tms_utime + t.tms_stime + t.tms_cutime + t.tms_cstime;
+ *ptime = (unsigned int)( clock_temp / clk_tck ) * 1000;
+ clock_temp %= clk_tck;
+ *ptime += (unsigned int)( (clock_temp * 1000) / clk_tck );
+#endif /* no _WIN32 */
+
+ return 1;
+}
+
+
+int
+get_elapsed( unsigned int *ptime )
+{
+#if defined(_WIN32)
+ /*
+ try timeBeginPeriod() and timeGetTime(),
+ or QueryPerformanceFrequency and QueryPerformanceCounter()
+ */
+ FILETIME FileTime;
+ ULARGE_INTEGER uli_temp;
+
+ GetSystemTimeAsFileTime( &FileTime );
+ uli_temp.LowPart = FileTime.dwLowDateTime;
+ uli_temp.HighPart = FileTime.dwHighDateTime;
+ *ptime = (unsigned int)( uli_temp.QuadPart / 10000U );
+#else
+ struct timeval timeval;
+
+ if ( gettimeofday( &timeval, NULL ) == -1 )
+ {
+ str_error = "gettimeofday() faild.";
+ return -1;
+ }
+ *ptime = (unsigned int)timeval.tv_sec * 1000;
+ *ptime += (unsigned int)timeval.tv_usec / 1000;
+#endif /* no _WIN32 */
+
+ return 1;
+}
--- /dev/null
+#include <assert.h>
+#include "shogi.h"
+
+
+#define CapW( PIECE, piece, pro_piece ) Xor( to, BB_W ## PIECE ); \
+ HAND_B -= flag_hand_ ## piece; \
+ BOARD[to] = -pro_piece
+
+#define CapB( PIECE, piece, pro_piece ) Xor( to, BB_B ## PIECE ); \
+ HAND_W -= flag_hand_ ## piece; \
+ BOARD[to] = pro_piece
+
+#define NocapNopro( PIECE, piece ) SetClear( BB_ ## PIECE ); \
+ BOARD[from] = piece
+
+#define NocapPro( PIECE , PRO_PIECE, piece ) Xor( from, BB_ ## PIECE ); \
+ Xor( to, BB_ ## PRO_PIECE ); \
+ BOARD[from] = piece
+
+
+void
+unmake_move_b( tree_t * restrict ptree, unsigned int move, int ply )
+{
+ int from = (int)I2From(move);
+ int to = (int)I2To(move);
+ int nrep = root_nrep + ply - 1;
+
+ HASH_KEY = ptree->rep_board_list[nrep];
+ MATERIAL = ptree->save_material[ply];
+
+ if ( from >= nsquare )
+ {
+ switch( From2Drop(from) )
+ {
+ case pawn: Xor( to, BB_BPAWN );
+ Xor( to-nfile, BB_BPAWN_ATK );
+ HAND_B += flag_hand_pawn; break;
+ case lance: Xor( to, BB_BLANCE );
+ HAND_B += flag_hand_lance; break;
+ case knight: Xor( to, BB_BKNIGHT );
+ HAND_B += flag_hand_knight; break;
+ case silver: Xor( to, BB_BSILVER );
+ HAND_B += flag_hand_silver; break;
+ case gold: Xor( to, BB_BGOLD );
+ Xor( to, BB_BTGOLD );
+ HAND_B += flag_hand_gold; break;
+ case bishop: Xor( to, BB_BBISHOP );
+ Xor( to, BB_B_BH );
+ HAND_B += flag_hand_bishop; break;
+ default: assert( From2Drop(from) == rook );
+ Xor( to, BB_BROOK );
+ Xor( to, BB_B_RD );
+ HAND_B += flag_hand_rook; break;
+ }
+
+ BOARD[to] = empty;
+ Xor( to, BB_BOCCUPY );
+ XorFile( to, OCCUPIED_FILE );
+ XorDiag2( to, OCCUPIED_DIAG2 );
+ XorDiag1( to, OCCUPIED_DIAG1 );
+ }
+ else {
+ const int ipiece_move = (int)I2PieceMove(move);
+ const int ipiece_cap = (int)UToCap(move);
+ const int is_promote = (int)I2IsPromote(move);
+ bitboard_t bb_set_clear;
+
+ BBOr( bb_set_clear, abb_mask[from], abb_mask[to] );
+ SetClear( BB_BOCCUPY );
+
+ if ( is_promote ) switch( ipiece_move )
+ {
+ case pawn: NocapPro( BPAWN, BPRO_PAWN, pawn );
+ Xor( to, BB_BPAWN_ATK );
+ Xor( to, BB_BTGOLD ); break;
+ case lance: NocapPro( BLANCE, BPRO_LANCE, lance );
+ Xor( to, BB_BTGOLD ); break;
+ case knight: NocapPro( BKNIGHT, BPRO_KNIGHT, knight );
+ Xor( to, BB_BTGOLD ); break;
+ case silver: NocapPro( BSILVER, BPRO_SILVER, silver );
+ Xor( to, BB_BTGOLD ); break;
+ case bishop: NocapPro( BBISHOP, BHORSE, bishop );
+ Xor( to, BB_B_HDK );
+ SetClear( BB_B_BH ); break;
+ default: assert( ipiece_move == rook );
+ NocapPro( BROOK, BDRAGON, rook );
+ Xor( to, BB_B_HDK );
+ SetClear( BB_B_RD ); break;
+ }
+ else switch ( ipiece_move )
+ {
+ case pawn: NocapNopro( BPAWN, pawn );
+ Xor( to-nfile, BB_BPAWN_ATK );
+ Xor( to, BB_BPAWN_ATK ); break;
+ case lance: NocapNopro( BLANCE, lance ); break;
+ case knight: NocapNopro( BKNIGHT, knight ); break;
+ case silver: NocapNopro( BSILVER, silver ); break;
+ case gold: NocapNopro( BGOLD, gold );
+ SetClear( BB_BTGOLD ); break;
+ case bishop: NocapNopro( BBISHOP, bishop );
+ SetClear( BB_B_BH ); break;
+ case rook: NocapNopro( BROOK, rook);
+ SetClear( BB_B_RD ); break;
+ case king: BOARD[from] = king;
+ SQ_BKING = (char)from;
+ SetClear( BB_B_HDK ); break;
+ case pro_pawn: NocapNopro( BPRO_PAWN, pro_pawn );
+ SetClear( BB_BTGOLD ); break;
+ case pro_lance: NocapNopro( BPRO_LANCE, pro_lance );
+ SetClear( BB_BTGOLD ); break;
+ case pro_knight: NocapNopro( BPRO_KNIGHT, pro_knight );
+ SetClear( BB_BTGOLD ); break;
+ case pro_silver: NocapNopro( BPRO_SILVER, pro_silver );
+ SetClear( BB_BTGOLD ); break;
+ case horse: NocapNopro( BHORSE, horse );
+ SetClear( BB_B_HDK );
+ SetClear( BB_B_BH ); break;
+ default: assert( ipiece_move == dragon );
+ NocapNopro( BDRAGON, dragon );
+ SetClear( BB_B_HDK );
+ SetClear( BB_B_RD ); break;
+ }
+
+ if ( ipiece_cap )
+ {
+ switch( ipiece_cap )
+ {
+ case pawn: CapW( PAWN, pawn, pawn );
+ Xor( to+nfile, BB_WPAWN_ATK ); break;
+ case lance: CapW( LANCE, lance, lance); break;
+ case knight: CapW( KNIGHT, knight, knight); break;
+ case silver: CapW( SILVER, silver, silver); break;
+ case gold: CapW( GOLD, gold, gold);
+ Xor( to, BB_WTGOLD ); break;
+ case bishop: CapW( BISHOP, bishop, bishop);
+ Xor( to, BB_W_BH ); break;
+ case rook: CapW( ROOK, rook, rook);
+ Xor( to, BB_W_RD ); break;
+ case pro_pawn: CapW( PRO_PAWN, pawn, pro_pawn);
+ Xor( to, BB_WTGOLD ); break;
+ case pro_lance: CapW( PRO_LANCE, lance, pro_lance);
+ Xor( to, BB_WTGOLD ); break;
+ case pro_knight: CapW( PRO_KNIGHT, knight, pro_knight);
+ Xor( to, BB_WTGOLD ); break;
+ case pro_silver: CapW(PRO_SILVER, silver, pro_silver);
+ Xor( to, BB_WTGOLD ); break;
+ case horse: CapW(HORSE, bishop, horse);
+ Xor( to, BB_W_HDK );
+ Xor( to, BB_W_BH ); break;
+ default: assert( ipiece_cap == dragon );
+ CapW(DRAGON, rook, dragon);
+ Xor( to, BB_W_HDK );
+ Xor( to, BB_W_RD ); break;
+ }
+ Xor( to, BB_WOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ }
+ else {
+ BOARD[to] = empty;
+ SetClearFile( from, to, OCCUPIED_FILE );
+ SetClearDiag1( from, to, OCCUPIED_DIAG1 );
+ SetClearDiag2( from, to, OCCUPIED_DIAG2 );
+ }
+ }
+
+ assert( exam_bb( ptree ) );
+}
+
+
+void
+unmake_move_w( tree_t * restrict ptree, unsigned int move, int ply )
+{
+ int from = (int)I2From(move);
+ int to = (int)I2To(move);
+ int nrep = root_nrep + ply - 1;
+
+ HASH_KEY = ptree->rep_board_list[nrep];
+ MATERIAL = ptree->save_material[ply];
+
+ if ( from >= nsquare )
+ {
+ switch( From2Drop(from) )
+ {
+ case pawn: Xor( to, BB_WPAWN );
+ Xor( to+nfile, BB_WPAWN_ATK );
+ HAND_W += flag_hand_pawn; break;
+ case lance: Xor( to, BB_WLANCE );
+ HAND_W += flag_hand_lance; break;
+ case knight: Xor( to, BB_WKNIGHT );
+ HAND_W += flag_hand_knight; break;
+ case silver: Xor( to, BB_WSILVER );
+ HAND_W += flag_hand_silver; break;
+ case gold: Xor( to, BB_WGOLD );
+ Xor( to, BB_WTGOLD );
+ HAND_W += flag_hand_gold; break;
+ case bishop: Xor( to, BB_WBISHOP );
+ Xor( to, BB_W_BH );
+ HAND_W += flag_hand_bishop; break;
+ default: assert( From2Drop(from) == rook );
+ Xor( to, BB_WROOK );
+ Xor( to, BB_W_RD );
+ HAND_W += flag_hand_rook; break;
+ }
+
+ BOARD[to] = empty;
+ Xor( to, BB_WOCCUPY );
+ XorFile( to, OCCUPIED_FILE );
+ XorDiag2( to, OCCUPIED_DIAG2 );
+ XorDiag1( to, OCCUPIED_DIAG1 );
+ }
+ else {
+ const int ipiece_move = (int)I2PieceMove(move);
+ const int ipiece_cap = (int)UToCap(move);
+ const int is_promote = (int)I2IsPromote(move);
+ bitboard_t bb_set_clear;
+
+ BBOr( bb_set_clear, abb_mask[from], abb_mask[to] );
+ SetClear( BB_WOCCUPY );
+
+ if ( is_promote ) switch( ipiece_move )
+ {
+ case pawn: NocapPro( WPAWN, WPRO_PAWN, -pawn );
+ Xor( to, BB_WPAWN_ATK );
+ Xor( to, BB_WTGOLD ); break;
+ case lance: NocapPro( WLANCE, WPRO_LANCE, -lance );
+ Xor( to, BB_WTGOLD ); break;
+ case knight: NocapPro( WKNIGHT, WPRO_KNIGHT, -knight );
+ Xor( to, BB_WTGOLD ); break;
+ case silver: NocapPro( WSILVER, WPRO_SILVER, -silver );
+ Xor( to, BB_WTGOLD ); break;
+ case bishop: NocapPro( WBISHOP, WHORSE, -bishop );
+ Xor( to, BB_W_HDK );
+ SetClear( BB_W_BH ); break;
+ default: assert( ipiece_move == rook );
+ NocapPro( WROOK, WDRAGON, -rook );
+ Xor( to, BB_W_HDK );
+ SetClear( BB_W_RD ); break;
+ }
+ else switch ( ipiece_move )
+ {
+ case pawn: NocapNopro( WPAWN, -pawn );
+ Xor( to+nfile, BB_WPAWN_ATK );
+ Xor( to, BB_WPAWN_ATK ); break;
+ case lance: NocapNopro( WLANCE, -lance ); break;
+ case knight: NocapNopro( WKNIGHT, -knight ); break;
+ case silver: NocapNopro( WSILVER, -silver ); break;
+ case gold: NocapNopro( WGOLD, -gold );
+ SetClear( BB_WTGOLD ); break;
+ case bishop: NocapNopro( WBISHOP, -bishop );
+ SetClear( BB_W_BH ); break;
+ case rook: NocapNopro( WROOK, -rook );
+ SetClear( BB_W_RD ); break;
+ case king: BOARD[from] = -king;
+ SQ_WKING = (char)from;
+ SetClear( BB_W_HDK ); break;
+ case pro_pawn: NocapNopro( WPRO_PAWN, -pro_pawn );
+ SetClear( BB_WTGOLD ); break;
+ case pro_lance: NocapNopro( WPRO_LANCE, -pro_lance );
+ SetClear( BB_WTGOLD ); break;
+ case pro_knight: NocapNopro( WPRO_KNIGHT,-pro_knight );
+ SetClear( BB_WTGOLD ); break;
+ case pro_silver: NocapNopro( WPRO_SILVER, -pro_silver );
+ SetClear( BB_WTGOLD ); break;
+ case horse: NocapNopro( WHORSE, -horse );
+ SetClear( BB_W_HDK );
+ SetClear( BB_W_BH ); break;
+ default: assert( ipiece_move == dragon );
+ NocapNopro( WDRAGON, -dragon );
+ SetClear( BB_W_HDK );
+ SetClear( BB_W_RD ); break;
+ }
+
+ if ( ipiece_cap )
+ {
+ switch( ipiece_cap )
+ {
+ case pawn: CapB( PAWN, pawn, pawn );
+ Xor( to-nfile, BB_BPAWN_ATK ); break;
+ case lance: CapB( LANCE, lance, lance ); break;
+ case knight: CapB( KNIGHT, knight, knight ); break;
+ case silver: CapB( SILVER, silver, silver ); break;
+ case gold: CapB( GOLD, gold, gold );
+ Xor( to, BB_BTGOLD ); break;
+ case bishop: CapB( BISHOP, bishop, bishop );
+ Xor( to, BB_B_BH ); break;
+ case rook: CapB( ROOK, rook, rook );
+ Xor( to, BB_B_RD ); break;
+ case pro_pawn: CapB( PRO_PAWN, pawn, pro_pawn );
+ Xor( to, BB_BTGOLD ); break;
+ case pro_lance: CapB( PRO_LANCE, lance, pro_lance );
+ Xor( to, BB_BTGOLD ); break;
+ case pro_knight: CapB( PRO_KNIGHT, knight, pro_knight );
+ Xor( to, BB_BTGOLD ); break;
+ case pro_silver: CapB( PRO_SILVER, silver, pro_silver );
+ Xor( to, BB_BTGOLD ); break;
+ case horse: CapB( HORSE, bishop, horse );
+ Xor( to, BB_B_HDK );
+ Xor( to, BB_B_BH ); break;
+ default: assert( ipiece_cap == dragon );
+ CapB( DRAGON, rook, dragon);
+ Xor( to, BB_B_HDK );
+ Xor( to, BB_B_RD ); break;
+ }
+ Xor( to, BB_BOCCUPY );
+ XorFile( from, OCCUPIED_FILE );
+ XorDiag1( from, OCCUPIED_DIAG1 );
+ XorDiag2( from, OCCUPIED_DIAG2 );
+ }
+ else {
+ BOARD[to] = empty;
+ SetClearFile( from, to, OCCUPIED_FILE );
+ SetClearDiag1( from, to, OCCUPIED_DIAG1 );
+ SetClearDiag2( from, to, OCCUPIED_DIAG2 );
+ }
+ }
+
+ assert( exam_bb( ptree ) );
+}
+
+
+#undef CapW
+#undef CapB
+#undef NocapNopro
+#undef NocapPro
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+#include "shogi.h"
+
+
+int
+ini_game( tree_t * restrict ptree, const min_posi_t *pmin_posi, int flag,
+ const char *str_name1, const char *str_name2 )
+{
+ bitboard_t bb;
+ int piece;
+ int sq, iret;
+
+ if ( flag & flag_history )
+ {
+ iret = open_history( str_name1, str_name2 );
+ if ( iret < 0 ) { return iret; }
+ }
+
+ if ( ! ( flag & flag_nofmargin ) )
+ {
+ fmg_misc = FMG_MISC;
+ fmg_cap = FMG_CAP;
+ fmg_drop = FMG_DROP;
+ fmg_mt = FMG_MT;
+ fmg_misc_king = FMG_MISC_KING;
+ fmg_cap_king = FMG_CAP_KING;
+ }
+
+ memcpy( ptree->posi.asquare, pmin_posi->asquare, nsquare );
+ ptree->move_last[0] = ptree->amove;
+ ptree->nsuc_check[0] = 0;
+ ptree->nsuc_check[1] = 0;
+ root_nrep = 0;
+ root_turn = pmin_posi->turn_to_move;
+ HAND_B = pmin_posi->hand_black;
+ HAND_W = pmin_posi->hand_white;
+ MATERIAL = 0;
+
+ BBIni( BB_BOCCUPY );
+ BBIni( BB_BPAWN );
+ BBIni( BB_BLANCE );
+ BBIni( BB_BKNIGHT );
+ BBIni( BB_BSILVER );
+ BBIni( BB_BGOLD );
+ BBIni( BB_BBISHOP );
+ BBIni( BB_BROOK );
+ BBIni( BB_BPRO_PAWN );
+ BBIni( BB_BPRO_LANCE );
+ BBIni( BB_BPRO_KNIGHT );
+ BBIni( BB_BPRO_SILVER );
+ BBIni( BB_BHORSE );
+ BBIni( BB_BDRAGON );
+ BBIni( BB_BTGOLD );
+ BBIni( BB_WOCCUPY );
+ BBIni( BB_WPAWN );
+ BBIni( BB_WLANCE );
+ BBIni( BB_WKNIGHT );
+ BBIni( BB_WSILVER );
+ BBIni( BB_WGOLD );
+ BBIni( BB_WBISHOP );
+ BBIni( BB_WROOK );
+ BBIni( BB_WPRO_PAWN );
+ BBIni( BB_WPRO_LANCE );
+ BBIni( BB_WPRO_KNIGHT );
+ BBIni( BB_WPRO_SILVER );
+ BBIni( BB_WHORSE );
+ BBIni( BB_WDRAGON );
+ BBIni( BB_WTGOLD );
+ BBIni( OCCUPIED_FILE );
+ BBIni( OCCUPIED_DIAG1 );
+ BBIni( OCCUPIED_DIAG2 );
+
+ for ( sq = 0; sq < nsquare; sq++ ) {
+ piece = BOARD[sq];
+ if ( piece > 0 ) {
+ Xor( sq, BB_BOCCUPY );
+ XorFile( sq, OCCUPIED_FILE );
+ XorDiag1( sq, OCCUPIED_DIAG1 );
+ XorDiag2( sq, OCCUPIED_DIAG2 );
+ switch ( piece )
+ {
+ case pawn: Xor( sq, BB_BPAWN ); break;
+ case lance: Xor( sq, BB_BLANCE ); break;
+ case knight: Xor( sq, BB_BKNIGHT ); break;
+ case silver: Xor( sq, BB_BSILVER ); break;
+ case rook: Xor( sq, BB_BROOK ); break;
+ case bishop: Xor( sq, BB_BBISHOP ); break;
+ case king: SQ_BKING = (char)sq; break;
+ case dragon: Xor( sq, BB_BDRAGON ); break;
+ case horse: Xor( sq, BB_BHORSE ); break;
+ case gold: Xor( sq, BB_BGOLD ); break;
+ case pro_pawn: Xor( sq, BB_BPRO_PAWN ); break;
+ case pro_lance: Xor( sq, BB_BPRO_LANCE ); break;
+ case pro_knight: Xor( sq, BB_BPRO_KNIGHT ); break;
+ case pro_silver: Xor( sq, BB_BPRO_SILVER ); break;
+ }
+ }
+ else if ( piece < 0 ) {
+ Xor( sq, BB_WOCCUPY );
+ XorFile( sq, OCCUPIED_FILE );
+ XorDiag1( sq, OCCUPIED_DIAG1 );
+ XorDiag2( sq, OCCUPIED_DIAG2 );
+ switch ( - piece )
+ {
+ case pawn: Xor( sq, BB_WPAWN ); break;
+ case lance: Xor( sq, BB_WLANCE ); break;
+ case knight: Xor( sq, BB_WKNIGHT ); break;
+ case silver: Xor( sq, BB_WSILVER ); break;
+ case rook: Xor( sq, BB_WROOK ); break;
+ case bishop: Xor( sq, BB_WBISHOP ); break;
+ case king: SQ_WKING = (char)sq; break;
+ case dragon: Xor( sq, BB_WDRAGON ); break;
+ case horse: Xor( sq, BB_WHORSE ); break;
+ case gold: Xor( sq, BB_WGOLD ); break;
+ case pro_pawn: Xor( sq, BB_WPRO_PAWN ); break;
+ case pro_lance: Xor( sq, BB_WPRO_LANCE ); break;
+ case pro_knight: Xor( sq, BB_WPRO_KNIGHT ); break;
+ case pro_silver: Xor( sq, BB_WPRO_SILVER ); break;
+ }
+ }
+ }
+
+ BBOr( BB_BTGOLD, BB_BPRO_PAWN, BB_BGOLD );
+ BBOr( BB_BTGOLD, BB_BPRO_LANCE, BB_BTGOLD );
+ BBOr( BB_BTGOLD, BB_BPRO_KNIGHT, BB_BTGOLD );
+ BBOr( BB_BTGOLD, BB_BPRO_SILVER, BB_BTGOLD );
+ BBOr( BB_B_HDK, BB_BHORSE, BB_BDRAGON );
+ BBOr( BB_B_HDK, BB_BKING, BB_B_HDK );
+ BBOr( BB_B_BH, BB_BBISHOP, BB_BHORSE );
+ BBOr( BB_B_RD, BB_BROOK, BB_BDRAGON );
+
+ BBOr( BB_WTGOLD, BB_WPRO_PAWN, BB_WGOLD );
+ BBOr( BB_WTGOLD, BB_WPRO_LANCE, BB_WTGOLD );
+ BBOr( BB_WTGOLD, BB_WPRO_KNIGHT, BB_WTGOLD );
+ BBOr( BB_WTGOLD, BB_WPRO_SILVER, BB_WTGOLD );
+ BBOr( BB_W_HDK, BB_WHORSE, BB_WDRAGON );
+ BBOr( BB_W_HDK, BB_WKING, BB_W_HDK );
+ BBOr( BB_W_BH, BB_WBISHOP, BB_WHORSE );
+ BBOr( BB_W_RD, BB_WROOK, BB_WDRAGON );
+
+ BB_BPAWN_ATK.p[0] = ( BB_BPAWN.p[0] << 9 ) & 0x7ffffffU;
+ BB_BPAWN_ATK.p[0] |= ( BB_BPAWN.p[1] >> 18 ) & 0x00001ffU;
+ BB_BPAWN_ATK.p[1] = ( BB_BPAWN.p[1] << 9 ) & 0x7ffffffU;
+ BB_BPAWN_ATK.p[1] |= ( BB_BPAWN.p[2] >> 18 ) & 0x00001ffU;
+ BB_BPAWN_ATK.p[2] = ( BB_BPAWN.p[2] << 9 ) & 0x7ffffffU;
+
+ BB_WPAWN_ATK.p[2] = ( BB_WPAWN.p[2] >> 9 );
+ BB_WPAWN_ATK.p[2] |= ( BB_WPAWN.p[1] << 18 ) & 0x7fc0000U;
+ BB_WPAWN_ATK.p[1] = ( BB_WPAWN.p[1] >> 9 );
+ BB_WPAWN_ATK.p[1] |= ( BB_WPAWN.p[0] << 18 ) & 0x7fc0000U;
+ BB_WPAWN_ATK.p[0] = ( BB_WPAWN.p[0] >> 9 );
+
+ MATERIAL = eval_material( ptree );
+ HASH_KEY = hash_func( ptree );
+
+ memset( ptree->hist_good, 0, sizeof(ptree->hist_good) );
+ memset( ptree->hist_tried, 0, sizeof(ptree->hist_tried) );
+ memset( hash_rejections_parent, 0, sizeof(hash_rejections_parent) );
+ memset( hash_rejections, 0, sizeof(hash_rejections) );
+
+ game_status &= ( flag_quiet | flag_reverse | flag_narrow_book
+ | flag_time_extendable | flag_learning
+ | flag_nobeep | flag_nostress | flag_nopeek
+ | flag_noponder | flag_noprompt );
+
+ sec_b_total = 0;
+ sec_w_total = 0;
+ sec_elapsed = 0;
+ last_root_value = 0;
+ n_nobook_move = 0;
+ last_pv.depth = 0;
+ last_pv.length = 0;
+ last_pv.a[0] = 0;
+ last_pv.a[1] = 0;
+
+ if ( InCheck( root_turn ) )
+ {
+ ptree->nsuc_check[1] = 1U;
+ if ( is_mate( ptree, 1 ) ) { game_status |= flag_mated; }
+ }
+
+ BBOr( bb, BB_BPAWN, BB_WPAWN );
+ BBOr( bb, bb, BB_BPRO_PAWN );
+ BBOr( bb, bb, BB_WPRO_PAWN );
+ npawn_box = npawn_max;
+ npawn_box -= PopuCount( bb );
+ npawn_box -= (int)I2HandPawn(HAND_B);
+ npawn_box -= (int)I2HandPawn(HAND_W);
+
+ BBOr( bb, BB_BLANCE, BB_WLANCE );
+ BBOr( bb, bb, BB_BPRO_LANCE );
+ BBOr( bb, bb, BB_WPRO_LANCE );
+ nlance_box = nlance_max;
+ nlance_box -= PopuCount( bb );
+ nlance_box -= (int)I2HandLance(HAND_B);
+ nlance_box -= (int)I2HandLance(HAND_W);
+
+ BBOr( bb, BB_BKNIGHT, BB_WKNIGHT );
+ BBOr( bb, bb, BB_BPRO_KNIGHT );
+ BBOr( bb, bb, BB_WPRO_KNIGHT );
+ nknight_box = nknight_max;
+ nknight_box -= PopuCount( bb );
+ nknight_box -= (int)I2HandKnight(HAND_B);
+ nknight_box -= (int)I2HandKnight(HAND_W);
+
+ BBOr( bb, BB_BSILVER, BB_WSILVER );
+ BBOr( bb, bb, BB_BPRO_SILVER );
+ BBOr( bb, bb, BB_WPRO_SILVER );
+ nsilver_box = nsilver_max;
+ nsilver_box -= PopuCount( bb );
+ nsilver_box -= (int)I2HandSilver(HAND_B);
+ nsilver_box -= (int)I2HandSilver(HAND_W);
+
+ BBOr( bb, BB_BGOLD, BB_WGOLD );
+ ngold_box = ngold_max;
+ ngold_box -= PopuCount( bb );
+ ngold_box -= (int)I2HandGold(HAND_B);
+ ngold_box -= (int)I2HandGold(HAND_W);
+
+ BBOr( bb, BB_BBISHOP, BB_WBISHOP );
+ BBOr( bb, bb, BB_BHORSE );
+ BBOr( bb, bb, BB_WHORSE );
+ nbishop_box = nbishop_max;
+ nbishop_box -= PopuCount( bb );
+ nbishop_box -= (int)I2HandBishop(HAND_B);
+ nbishop_box -= (int)I2HandBishop(HAND_W);
+
+ BBOr( bb, BB_BROOK, BB_WROOK );
+ BBOr( bb, bb, BB_BDRAGON );
+ BBOr( bb, bb, BB_WDRAGON );
+ nrook_box = nrook_max;
+ nrook_box -= PopuCount( bb );
+ nrook_box -= (int)I2HandRook(HAND_B);
+ nrook_box -= (int)I2HandRook(HAND_W);
+
+ iret = exam_tree( ptree );
+ if ( iret < 0 )
+ {
+ ini_game( ptree, &min_posi_no_handicap, 0, NULL, NULL );
+ return iret;
+ }
+
+ return 1;
+}
+
+
+int
+gen_legal_moves( tree_t * restrict ptree, unsigned int *p0 )
+{
+ unsigned int *p1;
+ int i, j, n;
+
+ p1 = GenCaptures( root_turn, p0 );
+ p1 = GenNoCaptures( root_turn, p1 );
+ p1 = GenCapNoProEx2( root_turn, p1 );
+ p1 = GenNoCapNoProEx2( root_turn, p1 );
+ p1 = GenDrop( root_turn, p1 );
+ n = (int)( p1 - p0 );
+
+ for ( i = 0; i < n; i++ )
+ {
+ MakeMove( root_turn, p0[i], 1 );
+ if ( InCheck( root_turn ) )
+ {
+ UnMakeMove( root_turn, p0[i], 1 );
+ p0[i] = 0;
+ continue;
+ }
+ if ( InCheck(Flip(root_turn)) )
+ {
+ ptree->nsuc_check[2] = (unsigned char)( ptree->nsuc_check[0] + 1U );
+ if ( ptree->nsuc_check[2] >= 6U
+ && ( detect_repetition( ptree, 2, Flip(root_turn), 3 )
+ == perpetual_check ) )
+ {
+ UnMakeMove( root_turn, p0[i], 1 );
+ p0[i] = 0;
+ continue;
+ }
+ }
+ UnMakeMove( root_turn, p0[i], 1 );
+ }
+
+ for ( i = 0; i < n; )
+ {
+ if ( ! p0[i] )
+ {
+ for ( j = i+1; j < n; j++ ) { p0[j-1] = p0[j]; }
+ n -= 1;
+ }
+ else { i++; }
+ }
+
+ return n;
+}
+
+
+/*
+ - detection of perpetual check is omitted.
+ - weak moves are omitted.
+*/
+int
+is_mate( tree_t * restrict ptree, int ply )
+{
+ int iret = 0;
+
+ assert( InCheck(root_turn) );
+
+ ptree->move_last[ply] = GenEvasion( root_turn, ptree->move_last[ply-1] );
+ if ( ptree->move_last[ply] == ptree->move_last[ply-1] ) { iret = 1; }
+
+ return iret;
+}
+
+
+int
+is_hand_eq_supe( unsigned int u, unsigned int uref )
+{
+#if 1
+/* aggressive superior correspondences are applied, that is:
+ * pawn <= lance, silver, gold, rook
+ * lance <= rook.
+ */
+ int nsupe;
+
+ if ( IsHandKnight(u) < IsHandKnight(uref)
+ || IsHandSilver(u) < IsHandSilver(uref)
+ || IsHandGold(u) < IsHandGold(uref)
+ || IsHandBishop(u) < IsHandBishop(uref)
+ || IsHandRook(u) < IsHandRook(uref) ) { return 0; }
+
+ nsupe = (int)I2HandRook(u) - (int)I2HandRook(uref);
+ nsupe += (int)I2HandLance(u) - (int)I2HandLance(uref);
+ if ( nsupe < 0 ) { return 0; }
+
+ nsupe += (int)I2HandSilver(u) - (int)I2HandSilver(uref);
+ nsupe += (int)I2HandGold(u) - (int)I2HandGold(uref);
+ nsupe += (int)I2HandPawn(u) - (int)I2HandPawn(uref);
+ if ( nsupe < 0 ) { return 0; }
+
+ return 1;
+#else
+ if ( IsHandPawn(u) >= IsHandPawn(uref)
+ && IsHandLance(u) >= IsHandLance(uref)
+ && IsHandKnight(u) >= IsHandKnight(uref)
+ && IsHandSilver(u) >= IsHandSilver(uref)
+ && IsHandGold(u) >= IsHandGold(uref)
+ && IsHandBishop(u) >= IsHandBishop(uref)
+ && IsHandRook(u) >= IsHandRook(uref) ) { return 1; }
+
+ return 0;
+#endif
+}
+
+
+/* weak moves are omitted. */
+int
+detect_repetition( tree_t * restrict ptree, int ply, int turn, int nth )
+{
+ const unsigned int *p;
+ unsigned int hand1, hand2;
+ int n, i, imin, counter, irep, ncheck;
+
+ ncheck = (int)ptree->nsuc_check[ply];
+ n = root_nrep + ply - 1;
+
+ /*if ( ncheck >= 6 )*/
+ if ( ncheck >= nth * 2 )
+ {
+ /* imin = n - ncheck*2; */
+ imin = n - ncheck*2 + 1;
+ if ( imin < 0 ) { imin = 0; }
+
+ ptree->move_last[ply] = GenEvasion( turn, ptree->move_last[ply-1] );
+ for ( p = ptree->move_last[ply-1]; p < ptree->move_last[ply]; p++ )
+ {
+ MakeMove( turn, *p, ply );
+
+ /* for ( i = n-1, counter = 0; i >= imin; i -= 2 ) */
+ for ( i = n-3, counter = 0; i >= imin; i -= 2 )
+ {
+ if ( ptree->rep_board_list[i] == HASH_KEY
+ && ptree->rep_hand_list[i] == HAND_B
+ && ++counter == nth )
+ /* && ncheck*2 - 1 >= n - i )*/
+ {
+ UnMakeMove( turn, *p, ply );
+ move_evasion_pchk = *p;
+ return perpetual_check;
+ }
+ }
+ UnMakeMove( turn, *p, ply );
+ }
+ }
+
+ irep = no_rep;
+ for ( i = n-4, counter = 0; i >= 0; i-- )
+ {
+ if ( ptree->rep_board_list[i] == HASH_KEY )
+ {
+ hand1 = HAND_B;
+ hand2 = ptree->rep_hand_list[i];
+
+ if ( (n-i) & 1 )
+ {
+ if ( irep == no_rep )
+ {
+ if ( turn )
+ {
+ if ( is_hand_eq_supe( hand2, hand1 ) )
+ {
+ irep = white_superi_rep;
+ }
+ }
+ else if ( is_hand_eq_supe( hand1, hand2 ) )
+ {
+ irep = black_superi_rep;
+ }
+ }
+ }
+ else if ( hand1 == hand2 )
+ {
+ if ( ++counter == nth )
+ {
+ if ( (ncheck-1)*2 >= n - i ) { return perpetual_check; }
+ else { return four_fold_rep; }
+ }
+ }
+ else if ( irep == no_rep )
+ {
+ if ( is_hand_eq_supe( hand1, hand2 ) )
+ {
+ irep = black_superi_rep;
+ }
+ else if ( is_hand_eq_supe( hand2, hand1 ) )
+ {
+ irep = white_superi_rep;
+ }
+ }
+ }
+ }
+
+ return irep;
+}
+
+
+int
+com_turn_start( tree_t * restrict ptree, int flag )
+{
+ const char *str_move;
+ unsigned int move, sec_total;
+ int iret, is_resign, value, ply;
+
+ if ( ! ( flag & flag_from_ponder ) )
+ {
+ assert( ! ( game_status & mask_game_end ) );
+
+ time_start = time_turn_start;
+
+ game_status |= flag_thinking;
+ iret = iterate( ptree, flag );
+ game_status &= ~flag_thinking;
+ if ( iret < 0 ) { return iret; }
+ }
+ if ( game_status & flag_suspend ) { return 1; }
+
+ move = last_pv.a[1];
+ value = root_turn ? -last_root_value : last_root_value;
+ str_move = str_CSA_move( move );
+
+ if ( value < -resign_threshold && last_pv.type != pv_fail_high )
+ {
+#if defined(DEKUNOBOU)
+ if ( dek_ngame )
+ {
+ dek_lost += 1;
+ Out( "Bonanza lost against Dekunobou\n" );
+ }
+#endif
+ is_resign = 1;
+ }
+ else {
+ is_resign = 0;
+
+#if defined(DEKUNOBOU)
+ if ( dek_ngame && ! is_resign
+ && value > ( MT_CAP_DRAGON * 3 ) / 2
+ && value > resign_threshold
+ && value != score_inferior )
+ {
+ is_resign = 1;
+ dek_win += 1;
+ Out( "Bonanza won against Dekunobou.\n" );
+ }
+ if ( dek_ngame && ! is_resign && value == -score_draw )
+ {
+ iret = make_move_root( ptree, move, ( flag_rep | flag_nomake_move ) );
+ if ( iret < 0 )
+ {
+ Out( "%s\n\n", str_move );
+ return iret;
+ }
+ else if ( iret == 2 )
+ {
+ is_resign = 1;
+ Out( "The game with Dekunobou is drawn.\n" );
+ }
+ }
+ if ( dek_ngame && ! is_resign && record_game.moves > 255 )
+ {
+ is_resign = 1;
+ Out( "The game with Dekunobou is interrupted...\n" );
+ }
+#endif
+ }
+
+#if defined(DBG_EASY)
+ if ( easy_move && easy_move != move )
+ {
+ out_warning( "EASY MOVE DITECTION FAILED." );
+ }
+#endif
+
+ /* send urgent outputs */
+ if ( is_resign )
+ {
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL )
+ {
+ iret = sckt_out( sckt_csa, "%%TORYO\n" );
+ if ( iret < 0 ) { return iret; }
+ }
+#endif
+ OutCsaShogi( "resign\n" );
+ OutDek( "%%TORYO\n" );
+ }
+ else {
+#if defined(CSA_LAN)
+ if ( sckt_csa != SCKT_NULL )
+ {
+ iret = sckt_out( sckt_csa, "%c%s\n", ach_turn[root_turn], str_move );
+ if ( iret < 0 ) { return iret; }
+ }
+#endif
+
+ OutCsaShogi( "move%s\n", str_move );
+ OutDek( "%c%s\n", ach_turn[root_turn], str_move );
+ }
+ OutBeep();
+
+ /* learning and stuff */;
+ ply = record_game.moves;
+ if ( ply < HASH_REG_HIST_LEN )
+ {
+ history_book_learn[ply].data &= ~( (1U<<31) | 0xffffU );
+ history_book_learn[ply].data |= (unsigned int)(value+32768);
+ history_book_learn[ply].move_responsible = move;
+ history_book_learn[ply].key_responsible = (unsigned int)HASH_KEY;
+ history_book_learn[ply].hand_responsible = (unsigned int)HAND_B;
+ }
+
+ iret = hash_learn( ptree, move, value, iteration_depth - 1 );
+ if ( iret < 0 ) { return iret; }
+
+ /* show search result and make a move */
+ if ( is_resign )
+ {
+ show_prompt();
+ game_status |= flag_resigned;
+ renovate_time( root_turn );
+ out_CSA( ptree, &record_game, MOVE_RESIGN );
+ sec_total = root_turn ? sec_w_total : sec_b_total;
+ str_move = "resign";
+ }
+ else {
+ show_prompt();
+ iret = make_move_root( ptree, move,
+ ( flag_rep | flag_time | flag_history
+ | flag_rejections ) );
+ if ( iret < 0 )
+ {
+ Out( "%s\n\n", str_move );
+ return iret;
+ }
+ sec_total = root_turn ? sec_b_total : sec_w_total;
+ }
+
+ OutCsaShogi( "info tt %03u:%02u\n", sec_total / 60U, sec_total % 60U );
+ Out( "%s '(%d%s) %03u:%02u/%03u:%02u elapsed: b%u, w%u\n",
+ str_move, value,
+ ( last_pv.type == pv_fail_high ) ? "!" : "",
+ sec_elapsed / 60U, sec_elapsed % 60U,
+ sec_total / 60U, sec_total % 60U,
+ sec_b_total, sec_w_total );
+
+ if ( ! is_resign )
+ {
+#if ! defined(NO_STDOUT)
+ iret = out_board( ptree, stdout, move, 0 );
+ if ( iret < 0 ) { return iret; }
+#endif
+ }
+
+ return 1;
+}
+
+
+#if defined(MNJ_LAN)
+int mnj_reset_tbl( int sd, unsigned int seed )
+{
+ double average, deviation, d;
+ unsigned int u;
+ int i, j;
+
+ if ( clear_trans_table() < 0 ) { return -1; }
+ ehash_clear();
+
+ if ( sd <= 0 )
+ {
+ for ( i = 0; i < MNJ_MASK + 1; i++ ) { mnj_tbl[i] = 0; }
+ return 1;
+ }
+
+ ini_rand( seed );
+
+ for( i = 0; i < MNJ_MASK + 1; i++ )
+ {
+ d = -6.0;
+
+ for ( j = 0; j < 12; j++ ) { d += (double)rand32() / (double)UINT_MAX; }
+ mnj_tbl[i] = (short)( (double)sd * d );
+ }
+
+ average = 0.0;
+ for ( i = 0; i < MNJ_MASK + 1; i++ ) { average += (double)mnj_tbl[i]; }
+ average /= (double)( MNJ_MASK + 1 );
+
+ deviation = 0.0;
+ for ( i = 0; i < MNJ_MASK + 1; i++ )
+ {
+ d = (double)mnj_tbl[i] - average;
+ deviation += d * d;
+ }
+ deviation = sqrt( deviation / (double)( MNJ_MASK + 1 ) );
+
+ if ( get_elapsed( &u ) < 0 ) { return -1; }
+ ini_rand( u );
+
+ Out( "\nThe normal distribution N(0,sd^2) is generated.\n" );
+ Out( " actual average: % .3f\n", average );
+ Out( " actual standard deviation: % .3f\n", deviation );
+ Out( "rand seed = %x\n", u );
+
+ return 1;
+}
+#endif
+
+
+void *
+memory_alloc( size_t nbytes )
+{
+#if defined(_WIN32)
+ void *p = VirtualAlloc( NULL, nbytes, MEM_COMMIT, PAGE_READWRITE );
+ if ( p == NULL ) { str_error = "VirturlAlloc() faild"; }
+#else
+ void *p = malloc( nbytes );
+ if ( p == NULL ) { str_error = "malloc() faild"; }
+#endif
+ return p;
+}
+
+
+int
+memory_free( void *p )
+{
+#if defined(_WIN32)
+ if ( VirtualFree( p, 0, MEM_RELEASE ) ) { return 1; }
+ str_error = "VirtualFree() faild";
+ return -2;
+#else
+ free( p );
+ return 1;
+#endif
+}
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "shogi.h"
+
+
+int
+is_move_valid( tree_t * restrict __ptree__, unsigned int move, int turn )
+{
+ tree_t * restrict ptree = __ptree__;
+ int from = (int)I2From(move);
+ int to = (int)I2To(move);
+ int piece_move;
+ unsigned int u;
+ bitboard_t bb;
+
+ if ( from < nsquare )
+ {
+ piece_move = (int)I2PieceMove(move);
+ if ( turn )
+ {
+ if ( BOARD[from] != -piece_move ) { return 0; }
+ if ( BOARD[to] != (int)UToCap(move) ) { return 0; }
+ }
+ else {
+ if ( BOARD[from] != piece_move ) { return 0; }
+ if ( BOARD[to] != -(int)UToCap(move) ) { return 0; }
+ }
+
+ switch ( piece_move )
+ {
+ case 0: return 0;
+
+ case lance: case bishop: case horse: case rook: case dragon:
+ BBOr( bb, BB_BOCCUPY, BB_WOCCUPY );
+ BBAnd( bb, bb, abb_obstacle[from][to] );
+ if ( BBToU( bb ) ) { return 0; }
+ break;
+ }
+
+ return 1;
+ }
+
+ if ( BOARD[to] ) { return 0; }
+ else {
+ u = turn ? HAND_W : HAND_B;
+ switch ( From2Drop(from) )
+ {
+ case pawn:
+ if ( ! IsHandPawn(u) ) { return 0; }
+ {
+ if ( turn )
+ {
+ u = BBToU( BB_WPAWN_ATK );
+ if ( ( mask_file1 >> aifile[to] ) & u ) { return 0; }
+ if ( IsMateWPawnDrop(__ptree__, to) ) { return 0; }
+ }
+ else {
+ u = BBToU( BB_BPAWN_ATK );
+ if ( ( mask_file1 >> aifile[to] ) & u ) { return 0; }
+ if ( IsMateBPawnDrop(__ptree__, to) ) { return 0; }
+ }
+ return 1;
+ }
+ case lance: if ( IsHandLance(u) ) { return 1; } break;
+ case knight: if ( IsHandKnight(u) ) { return 1; } break;
+ case silver: if ( IsHandSilver(u) ) { return 1; } break;
+ case gold: if ( IsHandGold(u) ) { return 1; } break;
+ case bishop: if ( IsHandBishop(u) ) { return 1; } break;
+ default: assert( From2Drop(from) == rook );
+ if ( IsHandRook(u) ) { return 1; } break;
+ }
+ }
+ return 0;
+}
+
+
+#define NpchkReturn(piece) if ( (n ## piece) > (n ## piece ## _max) ) { \
+ str_error = "too many " # piece "s"; \
+ return -2; }
+
+int
+exam_tree( const tree_t * restrict ptree )
+{
+ int npawn, nlance, nknight, nsilver, ngold, nbishop, nrook;
+ int nwking, nbking, isquare, ifile, irank, wcounter, bcounter;
+
+ /* total number of each piece */
+ npawn = (int)(I2HandPawn( HAND_B ) + I2HandPawn( HAND_W ));
+ nlance = (int)(I2HandLance( HAND_B ) + I2HandLance( HAND_W ));
+ nknight = (int)(I2HandKnight( HAND_B ) + I2HandKnight( HAND_W ));
+ nsilver = (int)(I2HandSilver( HAND_B ) + I2HandSilver( HAND_W ));
+ ngold = (int)(I2HandGold( HAND_B ) + I2HandGold( HAND_W ));
+ nbishop = (int)(I2HandBishop( HAND_B ) + I2HandBishop( HAND_W ));
+ nrook = (int)(I2HandRook( HAND_B ) + I2HandRook( HAND_W ));
+ nwking = nbking = 0;
+
+ for ( isquare = 0; isquare < nsquare; isquare++ )
+ switch ( abs( BOARD[isquare] ) )
+ {
+ case empty: break;
+ case pawn: case pro_pawn: npawn++; break;
+ case lance: case pro_lance: nlance++; break;
+ case knight: case pro_knight: nknight++; break;
+ case silver: case pro_silver: nsilver++; break;
+ case gold: ngold++; break;
+ case bishop: case horse: nbishop++; break;
+ case rook: case dragon: nrook++; break;
+ case king:
+ if ( BOARD[isquare] == king ) { nbking++; }
+ else { nwking++; }
+ break;
+ }
+ NpchkReturn( pawn ); NpchkReturn( lance );
+ NpchkReturn( knight ); NpchkReturn( silver );
+ NpchkReturn( gold ); NpchkReturn( bishop );
+ NpchkReturn( rook );
+ if ( nbking != 1 || nwking != 1 )
+ {
+ str_error = "invalid number of kings";
+ return -2;
+ }
+
+ /* double pawns */
+ for ( ifile = 0; ifile < 9; ifile++ )
+ {
+ bcounter = wcounter = 0;
+ for ( irank = 0; irank < 9; irank++ )
+ {
+ if ( BOARD[ irank*nfile+ifile ] == pawn ) { bcounter++; }
+ if ( BOARD[ irank*nfile+ifile ] == -pawn ) { wcounter++; }
+ }
+ if ( bcounter > 1 )
+ {
+ str_error = "two black pawns at a file";
+ return -2;
+ }
+ if ( wcounter > 1 )
+ {
+ str_error="two white pawns at a file";
+ return -2;
+ }
+ }
+
+ /* pieces can not move */
+ for ( isquare = 0; isquare < 9; isquare++ )
+ {
+ if ( BOARD[ isquare ] == pawn )
+ {
+ str_error = "black pawns in rank 1";
+ return -2;
+ }
+ if ( BOARD[ isquare ] == lance )
+ {
+ str_error = "black lances in rank 1";
+ return -2;
+ }
+ }
+ for ( isquare = 0; isquare < 18; isquare++ )
+ if ( BOARD[ isquare ] == knight )
+ {
+ str_error = "black knights in rank 1-2";
+ return -2;
+ }
+
+ for ( isquare = 72; isquare < 81; isquare++ )
+ {
+ if ( BOARD[ isquare ] == -pawn )
+ {
+ str_error = "white pawns in rank 9";
+ return -2;
+ }
+ if ( BOARD[ isquare ] == -lance )
+ {
+ str_error = "white lances in rank 9";
+ return -2;
+ }
+ }
+ for ( isquare = 63; isquare < 81; isquare++ )
+ if ( BOARD[ isquare ] == -knight )
+ {
+ str_error = "white knights in rank 8-9";
+ return -2;
+ }
+
+ if ( InCheck( Flip(root_turn) ) )
+ {
+ str_error = str_king_hang;
+ return -2;
+ }
+
+ assert( exam_bb( ptree ) );
+
+ return 1;
+}
+
+#undef NpchkReturn