/*>>> sanhsh.c: SAN project hash code generation */

/* Revised: 1993.09.14 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "sandef.h"
#include "sanvar.h"

#include "sandsp.h"
#include "sanhsh.h"
#include "sanutl.h"

/**** Locals */

/* the psuedorandom generator seed */

static uliT hash_ps_seed;

/* macro for calculating a main hash xor record address */

#define mhxpoint(cp, sq) (mhxp_base + (((cp) << sqQ) + (sq)))

/* main hash table exclusive-or record storage of color-piece/square codes */

static hxptrT mhxp_base;

/* main hash table exclusive-or record storage of castling availabilities */

static hxT mhxp_caiv[caiL];

/* main hash table exclusive-or record storage of en passant target files */

static hxT mhxp_eptf[fileL];

/*--> SANHashColorPieceSq: change single index/position signature pair */
nonstatic
void
SANHashColorPieceSq (cpT cp, sqT sq)
{
  hxptrT hxptr;

/* important: cp_wp <= cp <= cp_bk */

  hxptr = mhxpoint (cp, sq);
  curr_e.e_mhca ^= hxptr->hx_hcpa;
  curr_e.e_mhcs ^= hxptr->hx_hcps;

  return;
}

/*--> SANHashCastlingAvailability: change castling availability signatures */
nonstatic
void
SANHashCastlingAvailability (caiT cai)
{
  curr_e.e_mhca ^= mhxp_caiv[cai].hx_hcpa;
  curr_e.e_mhcs ^= mhxp_caiv[cai].hx_hcps;

  return;
}

/*--> SANHashEnPassantTargetFile: change en passant file signatures */
nonstatic
void
SANHashEnPassantTargetFile (void)
{
  hxptrT hxptr;

/* note that the current ep target square must not be nil */

  hxptr = &mhxp_eptf[map_file_sq (curr_e.e_epsq)];
  curr_e.e_mhca ^= hxptr->hx_hcpa;
  curr_e.e_mhcs ^= hxptr->hx_hcps;

  return;
}

/*--> SANHashColorPieceSqSq: change two index/position signatures */
nonstatic
void
SANHashColorPieceSqSq (cpT cp, sqT sq0, sqT sq1)
{
  hxptrT hxptr;

/* important: cp_wp <= cp <= cp_bk */

  hxptr = mhxpoint (cp, sq0);
  curr_e.e_mhca ^= hxptr->hx_hcpa;
  curr_e.e_mhcs ^= hxptr->hx_hcps;

  hxptr = mhxpoint (cp, sq1);
  curr_e.e_mhca ^= hxptr->hx_hcpa;
  curr_e.e_mhcs ^= hxptr->hx_hcps;

  return;
}

/*--> SANHashCreate: create main hash subsystem index/position signatures */
nonstatic
void
SANHashCreate (void)
{
  cpT cp;
  sqT sq;
  caiT cai;

/* clear the main hash address and signature */

  curr_e.e_mhca = 0;
  curr_e.e_mhcs = 0;

/* create the main hash address and signature from the local board */

  for (sq = sq_a1; sq <= sq_h8; sq++)
    if ((cp = gb.bv[sq]) != cp_v0)
      SANHashColorPieceSq (cp, sq);

/* fold in castling availability */

  for (cai = cai_wk; cai <= cai_bq; cai++)
    if (curr_e.e_cast & (bit << cai))
      SANHashCastlingAvailability (cai);

/* fold in en passant target file */

  if (curr_e.e_epsq != sq_nil)
    SANHashEnPassantTargetFile ();

  return;
}

/*--> SANHashDisplayGenerationTables: display the hash generation table set */
nonstatic
void
SANHashDisplayGenerationTables (void)
{
  cT c;
  pT p;
  cpT cp;
  fileT file;
  rankT rank;
  sqT sq;
  caiT cai;
  hxptrT hxptr;
  hcpaT hcpa;
  hcpsT hcps;

  SANDspLine ("castling   Address  Signature");
  SANDspLine ("--         -------- --------");
  for (cai = cai_wk; cai <= cai_bq; cai++)
    {
      hcpa = mhxp_caiv[cai].hx_hcpa;
      hcps = mhxp_caiv[cai].hx_hcps;
      SANDspColor (cai / flankL);
      SANDspPiece ((cai % flankL) ? p_q : p_k);
      SANDspStr ("         ");
      sprintf (stv, "%08lx", hcpa);
      SANDspSTV ();
      SANDspChar (' ');
      sprintf (stv, "%08lx", hcps);
      SANDspSTV ();
      SANDspNL ();
    };
  SANDspNL ();

  SANDspLine ("ep file    Address  Signature");
  SANDspLine ("-          -------- --------");
  for (file = file_a; file <= file_h; file++)
    {
      hcpa = mhxp_eptf[file].hx_hcpa;
      hcps = mhxp_eptf[file].hx_hcps;
      SANDspChar (acfv[file]);
      SANDspStr ("          ");
      sprintf (stv, "%08lx", hcpa);
      SANDspSTV ();
      SANDspChar (' ');
      sprintf (stv, "%08lx", hcps);
      SANDspSTV ();
      SANDspNL ();
    };
  SANDspNL ();

  SANDspLine ("cp sq      Address  Signature");
  SANDspLine ("-- --      -------- --------");
  for (c = c_w; c <= c_b; c++)
    for (p = p_p; p <= p_k; p++)
      {
	cp = cv_cp_cpv[c][p];
	for (file = file_a; file <= file_h; file++)
	  for (rank = rank_1; rank <= rank_8; rank++)
	    {
	      sq = map_sq_rank_file (rank, file);
	      hxptr = mhxpoint (cp, sq);
	      hcpa = hxptr->hx_hcpa;
	      hcps = hxptr->hx_hcps;
	      SANDspColor (c);
	      SANDspPiece (p);
	      SANDspChar (' ');
	      SANDspSq (sq);
	      SANDspStr ("      ");
	      sprintf (stv, "%08lx", hcpa);
	      SANDspSTV ();
	      SANDspChar (' ');
	      sprintf (stv, "%08lx", hcps);
	      SANDspSTV ();
	      SANDspNL ();
	    };
      };
  SANDspNL ();

  return;
}

/*--> SANHashPSNonNegativeWord: psuedorandom positive 16 bit word */
static
  siT
SANHashPSNonNegativeWord (void)
{
  hash_ps_seed = (hash_ps_seed * 1103515245L) + 12345L;

  return ((siT) ((hash_ps_seed >> wordW) & 0x7fff));
}

/*--> SANHashPSByte: return psuedorandom 8 bit byte (in a word) */
static
  siT
SANHashPSByte (void)
{

  return ((SANHashPSNonNegativeWord () >> nybbW) & byteM);
}

/*--> SANHashPSWord: return psuedorandom 16 bit word (in a long word) */
static
  liT
SANHashPSWord (void)
{
  liT n;

  n = (((liT) SANHashPSByte ()) << byteW) | ((liT) SANHashPSByte ());

  return (n);
}

/*--> SANHashPSLongWord: return psuedorandom 32 bit word */
static
  liT
SANHashPSLongWord (void)
{
  liT n;

  n = (SANHashPSWord () << wordW) | (SANHashPSWord () & wordM);

  return (n);
}

/*--> SANHashInit: initialize main hash table subsystem (called once) */
nonstatic
void
SANHashInit (void)
{
  hxptrT hxptr;
  cpT cp;
  sqT sq;
  caiT cai;
  fileT file;

/* set the hash psuedorandom seed to generate the canonical table sequence */

  hash_ps_seed = 1;

/* allocate hash color-piece/square xor data */

  mhxp_base = (hxptrT) SANMemGrab (sizeof (hxT) * rcpL * sqL);

/* initialize (constant) color-piece/square hash xor data */

  for (cp = cp_wp; cp <= cp_bk; cp++)
    for (sq = sq_a1; sq <= sq_h8; sq++)
      {
	hxptr = mhxpoint (cp, sq);
	hxptr->hx_hcpa = SANHashPSLongWord ();
	hxptr->hx_hcps = SANHashPSLongWord ();
      };

/* initialize (constant) castling availability hash xor data */

  for (cai = cai_wk; cai <= cai_bq; cai++)
    {
      mhxp_caiv[cai].hx_hcpa = SANHashPSLongWord ();
      mhxp_caiv[cai].hx_hcps = SANHashPSLongWord ();
    };

/* initialize (constant) en passant target file hash xor data */

  for (file = file_a; file <= file_h; file++)
    {
      mhxp_eptf[file].hx_hcpa = SANHashPSLongWord ();
      mhxp_eptf[file].hx_hcps = SANHashPSLongWord ();
    };

  return;
}

/*--> SANHashTerm: terminate main hash table subsystem (called once) */
nonstatic
void
SANHashTerm (void)
{
/* release hash xor storage */

  SANMemFree (mhxp_base);

  return;
}

/*<<< sanhsh.c: EOF */
