/* * CHEST, chess analyst. For Copyright notice read file "COPYRIGHT". * * $Source: /home/heiner/ca/chest/RCS/board.h,v $ * $Id: board.h,v 3.24 1999/10/13 22:28:25 heiner Exp $ * * Boards, moves and move lists */ #ifndef CHEST_board_h_INCLUDED #define CHEST_board_h_INCLUDED #include "types.h" #include "xatt.h" typedef struct Field Field; typedef union FieldSet FieldSet; typedef union PackedBoard PackedBoard; typedef struct DoDaStack DoDaStack; typedef struct Board Board; typedef struct Move Move; typedef struct Movelist Movelist; #if USE_XATT # include "xatt_global.h" #endif /* * Note: * + If figure related declarations are changed, these * changes must be applied to "xatt_global.h", too. */ struct Field { Colour f_c; Figure f_f; int8 f_pos64; /* 0..63 or -1, codes line and column */ int8 f_idx; /* index into piece list, or -1 */ #if ! USE_XATT PieceSet f_datt; /* direct attacks */ PieceSet f_iatt; /* indirect attacks */ char f_unused[4]; /* filler to 16 bytes */ #else # if XATT_TST_LAZY xAttAI f_ai; # else PieceSet f_xAtt[ XATT_MAX_DEPTH+1 ]; /* implied border check (!) */ # endif #endif }; /* * == Macros being used to access attack information: == */ /* * ---------------- * -- Internals: -- * ---------------- */ /* * Configuration dependant direct access of attack information: * (may be invalid or NOT sync'ed) */ #if ! USE_XATT # define F_ATTioXX(bp,fp,depth,type) F_ATTioXX_##depth(bp,fp) # define F_ATTioXX_0(bp,fp) ((fp)->f_datt) # define F_ATTioXX_1(bp,fp) ((fp)->f_iatt) #else # define F_ATTioXX(bp,fp,depth,type) (XATT_ai_atts(bp,fp)[depth]) #endif /* * General direct access of attack information: * (may be invalid or NOT sync'ed) */ #define F_DATTioXX(bp,fp,type) F_ATTioXX(bp,fp,0,type) #define F_IATTioXX(bp,fp,type) F_ATTioXX(bp,fp,1,type) /* * Write access of attack information: * + sync'ed. * + count'ed. */ #define F_ATTioWR(bp,fp,depth,type) \ ( \ *( XATT_F_acc(bp,fp,depth,type,XATT_OP_wr,TOK_C) \ &F_ATTioXX(bp,fp,depth,type) \ ) \ ) #define F_ATTwrCnt(bp,fp,depth,type) \ ( \ *( XATT_F_cnt(bp,fp,depth,type,XATT_OP_wr,TOK_C) \ &F_ATTioWR(bp,fp,depth,type) \ ) \ ) /* * Read access of attack information: * + sync'ed. * + count'ed. */ #define F_ATTioRD(bp,fp,depth,type) \ ( XATT_F_acc(bp,fp,depth,type,XATT_OP_rd,TOK_C) \ ((const PieceSet)F_ATTioXX(bp,fp,depth,type)) \ ) #define F_ATTrdCnt(bp,fp,depth,type) \ ( XATT_F_cnt(bp,fp,depth,type,XATT_OP_rd,TOK_C) \ F_ATTioRD(bp,fp,depth,type) \ ) /* * ============== * == Exports: == * ============== */ /* WRITE access (counted): */ #define F_ATTwr(bp,fp,depth) F_ATTwrCnt(bp,fp,depth,XATT_TP_extern) #define F_DATTwr(bp,fp) F_ATTwr(bp,fp,0) #define F_IATTwr(bp,fp) F_ATTwr(bp,fp,1) /* READ access (counted): */ #define F_ATTrd(bp,fp,depth) F_ATTrdCnt(bp,fp,depth,XATT_TP_extern) #define F_DATTrd(bp,fp) F_ATTrd(bp,fp,0) #define F_IATTrd(bp,fp) F_ATTrd(bp,fp,1) /* DEFAULT [read] access (counted): */ #define F_DATTbp(bp,fp) F_DATTrd(bp,fp) #define F_IATTbp(bp,fp) F_IATTrd(bp,fp) /* * Convention: * + For the use of the following two macros, we assume the existence * of a variable named 'bp' of type 'Board*', which points at * the desired board! */ #define F_DATT(fp) F_DATTbp(bp,fp) /*!*/ #define F_IATT(fp) F_IATTbp(bp,fp) /*!*/ /* * == ----------------------------------------------- == */ /* * A "FieldSet" is a 64-bit vector, addressed by Pos64. * It codes a set of positions e.g. occupied by white pawns. * In order to copy a FieldSet, or test it for emptyness, * it is best to access it by large, i.e. "uint32" parts. * In order to access single bits (given a Pos64), it might be * best to use "uint8" components on a byte-addressed machine. * Modern RISC architectures may do word addressing as well. * On HPPA and R4400 there is little or no difference. * * In order to make the C-initializer portable, we make * the byte-wise version the first one, and initialize that. * Runtime access of single bits has to use the "fs_line" version, * while operations on the complete Set may use "fs_long". */ union FieldSet /* set-of-pos64 */ { uint8 fs_line[8]; /* [lin] Set-of-Col (must be first) */ uint32 fs_long[2]; /* (must be second) */ }; /* * A packed board contains 4 bit (a nibble) for each of the 64 fields. * Coding is normalized such that an empty field is coded by a true zero. * On byte addressed machines it is best to manipulate with byte addressing, * else it is better to use word addressing. * Because of byte sex we must not mix both methods. */ #ifndef PB_IS_BYT_ADDRESSED # define PB_IS_BYT_ADDRESSED 1 /* CF */ #endif union PackedBoard /* 4 bit for each Field */ { #if PB_IS_BYT_ADDRESSED uint8 pb_byte[64/2]; /* normally addressing here */ #endif uint32 pb_long[64/8]; /* copy/compare here */ }; #if PB_IS_BYT_ADDRESSED typedef uint8 PbUnit; #else typedef uint32 PbUnit; #endif /* construct a nibble value */ #define PB_cf_val(c,f) ( (((f)-no_figure) << 1) | (((c)-empty) & 01) ) #define PB_fp_val(fp) PB_cf_val((fp)->f_c, (fp)->f_f) /* nibble addressing */ #if PB_IS_BYT_ADDRESSED # define PB_64_inx(n) ((n) >> 1) # define PB_64_shift(n) (((n) & 01) << 2) # define PB_64_P(pbp,n) (&((pbp)->pb_byte[PB_64_inx(n)])) #else # define PB_64_inx(n) ((n) >> 3) # define PB_64_shift(n) (((n) & 07) << 2) # define PB_64_P(pbp,n) (&((pbp)->pb_long[PB_64_inx(n)])) #endif /* masking and clearing */ #define PB_sh_mask(n) (((uint32)0x0f) << (n)) #define PB_64_mask(n) PB_sh_mask(PB_64_shift(n)) #define PB_64_Clr(p,n) (*PB_64_P(p,n) &= ~PB_64_mask(n)) /* * The downdate stack is part of the board. * For details cf. "move.c". */ typedef int16 DDelem; /* all DD arguments fit into this */ #define MAX_DD_PER_MOVE (5+2+2 + 2+5+2 + 1+1 +6) #define MAX_DD_ELEMS (1 + (MAX_DD_PER_MOVE * 2 * MAX_ANA_DEPTH)) struct DoDaStack { DDelem* dds_ptr; /* lowest used in "dds_stack" */ DDelem dds_stack[MAX_DD_ELEMS]; /* grow-down downdate stack */ }; struct Board { Field b_f[B_SIZE]; Colour b_tomove; /* who is to move next */ Position b_ep; /* possible to beat by e.p. */ Castle b_castle[2]; /* indexed by Colour */ Position b_piece[2*MAX_PIECE]; /* piece list for both */ int8 b_max_piece[2]; /* filled slots in b_piece */ int8 b_cur_piece[2]; /* nonempty slots in b_piece */ FieldSet b_fig; /* all non-empty */ FieldSet b_bau[2]; /* all B [colour] */ PackedBoard b_packed; /* especially for memory */ #if WITH_ZHASH Zhash b_zhash; /* Zobrist hash code */ #endif int8 b_fig_cnt[2][MAX_FIGURES]; /* # of figs by colour & type */ #if ( USE_XATT && XATT_LAZY ) xAttLazy b_lazy; /* "xAtt" lazy management */ #endif /* FFS: */ PieceSet b_fig_set[2][MAX_FIGURES]; /* set(figs) by colour & type */ DoDaStack b_ddstk; /* history: down date stack */ }; #define K_POS(bp,c) ((bp)->b_piece[ K_IDX(c) ]) #define K_FP(bp,c) (&( bp->b_f[ K_POS(bp,c) ] )) #define MK_AddrDiff(fp1,fp2) (((char*)(fp1)) - ((char*)(fp2))) #define MK_AddrStep(fp,delta) ((Field*) (((char*)(fp)) + (delta))) #define COPY_BOARD(bp_src,bp_dst) \ { \ *(bp_dst) = *(bp_src); \ } Extern void chk_board (const Board*, const char*, int, Bool wantcore); Extern Bool ok_inp_board (Xconst Board*); /* on clean input */ #if PROD_LEV < 2 # define CHK_BOARD(bp) if( f_debug ) chk_board(bp, __FILE__, __LINE__, 1) ; #else # define CHK_BOARD(bp) { /*empty*/ } #endif #define in_check(bp) ( F_DATT(K_FP(bp, (bp)->b_tomove)) \ & COLOUR_MASK(opp_colour((bp)->b_tomove)) ) struct Move { Position m_from; Position m_to; Figure m_fig; /* what results by the move */ int8 m_idx; /* the moving piece's index */ uint8 m_attr; /* e.g. checking */ int8 m_spare; int16 m_value; /* for answer-heuristic */ int16 m_value2; /* for answer-heuristic */ Move* m_next; }; /* * Values (bits) found in "m_attr": */ #define MA_DCK 0x01 /* direct check */ #define MA_ICK 0x02 /* indirect check */ #define MA_ECK 0x04 /* special e.p. check (through beaten) */ #define MA_NCK 0x08 /* near (direct) check */ #define MA__CK 0x0f #define MA_SKIP 0x10 /* marked for skipping */ #ifndef MAX_MOVES # define MAX_MOVES 222 /* CF FFS: max known is 218 */ #endif struct Movelist { uint32 l_attr; PieceSet l_hasckmv; /* who has a move with MA__CK */ Move* l_free; /* allocation point */ Move* l_first; /* root of linked list */ Move l_m[MAX_MOVES]; }; /* * Values (bits) found in "l_attr": */ #define LA_CK 0x01 /* MA__CK computed */ #define clear_list(lp) \ ((lp)->l_attr = 0, (lp)->l_hasckmv = 0, \ (lp)->l_free = (lp)->l_m, (lp)->l_first = 0) #define empty_list(lp) ((lp)->l_free == (lp)->l_m) #define list_length(lp) ((lp)->l_free - (lp)->l_m) #define formoves(lp,p) for( (p) = (lp)->l_first ; (p) ; (p)=(p)->m_next ) /* * Use "app_move" macro after "clear_list()", only, * and close the list via "mg_link()". */ #define app_move(p,lp) (*((lp)->l_free)++ = *(p)) /* * "ebc" == EscSet blocked completely * Map the center of an escape-environment "e" [Pos64], * and a blocking square [Pos64] to the set of all Pos64, * from which the complete environment is hidden by the blocker, * where the blocking Position itself is not considered blocked. * For better locality we use an index table. * Index 0 is fixed to the empty set. */ Extern Iconst uint16 ebc_inx[64][64]; /* [e][b], []ebc_tab */ Extern Iconst FieldSet ebc_tab[64*64]; /* [ebc_inx] */ #define ebc_from(e,b) (ebc_tab[ebc_inx[e][b]]) #endif /* ndef CHEST_board_h_INCLUDED */