/*>>> sanmsc.c: SAN project miscellaneous routines */

/* Revised: 1994.02.10 */

#include <stdio.h>
#include <string.h>

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

#include "sanatk.h"
#include "sanmsc.h"

/*--> SANSetMaterial: calculate material components */
nonstatic
void
SANSetMaterial (void)
{
  sqT sq;
  cpT cp;

  cpmv[c_w] = cpmv[c_b] = 0;
  for (sq = sq_a1; sq <= sq_h8; sq++)
    {
      cp = gb.bv[sq];
      if (cp != cp_v0)
	cpmv[cv_c_cpv[cp]] += valcpv[cp];
    };

  return;
}

/*--> SANSetPieceVector: set the piece location and board index vectors */
nonstatic
void
SANSetPieceVector (void)
{
  sqT sq;
  rcT c;
  pT p;
  cpT cp;
  siT i, n;

  for (c = c_w; c <= c_b; c++)
    {
      plv[c][kingslot] = sq_nil;
      n = 0;

      for (sq = sq_a1; sq <= sq_h8; sq++)
	{
	  cp = gb.bv[sq];
	  if (cv_c_cpv[cp] == c)
	    {
	      p = cv_p_cpv[cp];
	      switch (p)
		{
		case p_p:
		case p_n:
		case p_b:
		case p_r:
		case p_q:
		  if (plv[c][kingslot] == sq_nil)
		    {
		      if (n < (pmaxL - 1))
			{
			  plv[c][n + 1] = sq;
			  n++;
			};
		    }
		  else
		    {
		      if (n < pmaxL)
			{
			  plv[c][n] = sq;
			  n++;
			};
		    };
		  break;

		case p_k:
		  if (plv[c][kingslot] == sq_nil)
		    {
		      plv[c][kingslot] = sq;
		      n++;
		    };
		  break;
		};
	    };
	};

      plnv[c] = n;
      for (i = 0; i < n; i++)
	biv[plv[c][i]] = i;
    };

  return;
}

/*--> SANAddPiece: add a piece (not king) to the piece vector */
nonstatic
void
SANAddPiece (sqT sq)
{
  cT c;

  c = cv_c_cpv[gb.bv[sq]];
  plv[c][biv[sq] = plnv[c]++] = sq;

  return;
}

/*--> SANSubPiece: subtract a piece (not king) from the piece vector */
nonstatic
void
SANSubPiece (sqT sq)
{
  cT c;
  siT i, n;


  n = --plnv[c = cv_c_cpv[gb.bv[sq]]];
  for (i = biv[sq]; i < n; i++)
    biv[plv[c][i] = plv[c][i + 1]]--;

  return;
}

/*--> SANCensus: census report */
nonstatic
cenT
SANCensus (void)
{
  cenT cen;
  fileT file;
  sqT sq;
  cpT cp;
  siT ncpv[cpL], wps, bps;

/* set default (position legal; okay to attempt generation) */

  cen = cen_lgl;

/* enumerate */

  for (cp = 0; cp < cpL; cp++)
    ncpv[cp] = 0;

  for (sq = sq_a1; sq <= sq_h8; sq++)
    ncpv[gb.bv[sq]]++;

  wps = 8 - ncpv[cp_wp];
  bps = 8 - ncpv[cp_bp];

/* test white king non-unique */

  if (cen == cen_lgl)
    if (ncpv[cp_wk] != 1)
      cen = cen_wkn;

/* test black king non-unique */

  if (cen == cen_lgl)
    if (ncpv[cp_bk] != 1)
      cen = cen_bkn;

/* test white kingside castling */

  if (cen == cen_lgl)
    if (curr_e.e_cast & cast_wk)
      if ((gb.bv[sq_e1] != cp_wk) || (gb.bv[sq_h1] != cp_wr))
	cen = cen_wck;

/* test black kingside castling */

  if (cen == cen_lgl)
    if (curr_e.e_cast & cast_bk)
      if ((gb.bv[sq_e8] != cp_bk) || (gb.bv[sq_h8] != cp_br))
	cen = cen_bck;

/* test white queenside castling */

  if (cen == cen_lgl)
    if (curr_e.e_cast & cast_wq)
      if ((gb.bv[sq_e1] != cp_wk) || (gb.bv[sq_a1] != cp_wr))
	cen = cen_wcq;

/* test black queenside castling */

  if (cen == cen_lgl)
    if (curr_e.e_cast & cast_bq)
      if ((gb.bv[sq_e8] != cp_bk) || (gb.bv[sq_a8] != cp_br))
	cen = cen_bcq;

/* test white pawn surplus */

  if (cen == cen_lgl)
    if (ncpv[cp_wp] > 8)
      cen = cen_wps;

/* test black pawn surplus */

  if (cen == cen_lgl)
    if (ncpv[cp_bp] > 8)
      cen = cen_bps;

/* test white men surplus */

  if (cen == cen_lgl)
    {
      if (ncpv[cp_wq] > 1)
	wps -= (ncpv[cp_wq] - 1);
      if (ncpv[cp_wr] > 2)
	wps -= (ncpv[cp_wr] - 2);
      if (ncpv[cp_wb] > 2)
	wps -= (ncpv[cp_wb] - 2);
      if (ncpv[cp_wn] > 2)
	wps -= (ncpv[cp_wn] - 2);
      if (wps < 0)
	cen = cen_wms;
    };

/* test black men surplus */

  if (cen == cen_lgl)
    {
      if (ncpv[cp_bq] > 1)
	bps -= (ncpv[cp_bq] - 1);
      if (ncpv[cp_br] > 2)
	bps -= (ncpv[cp_br] - 2);
      if (ncpv[cp_bb] > 2)
	bps -= (ncpv[cp_bb] - 2);
      if (ncpv[cp_bn] > 2)
	bps -= (ncpv[cp_bn] - 2);
      if (bps < 0)
	cen = cen_bms;
    };

/* test white pawn misplacement */

  if (cen == cen_lgl)
    if (ncpv[cp_wp] > 0)
      {
	file = file_a;
	while ((cen == cen_lgl) && (file <= file_h))
	  if ((gb.bv[map_sq_rank_file (rank_1, file)] == cp_wp) ||
	      (gb.bv[map_sq_rank_file (rank_8, file)] == cp_wp))
	    cen = cen_wpm;
	  else
	    file++;
      };

/* test black pawn misplacement */

  if (cen == cen_lgl)
    if (ncpv[cp_bp] > 0)
      {
	file = file_a;
	while ((cen == cen_lgl) && (file <= file_h))
	  if ((gb.bv[map_sq_rank_file (rank_1, file)] == cp_bp) ||
	      (gb.bv[map_sq_rank_file (rank_8, file)] == cp_bp))
	    cen = cen_bpm;
	  else
	    file++;
      };

/* test white passive check */

  if (cen == cen_lgl)
    if ((curr_e.e_pasc == c_w) && SANAttack (c_b, plv[c_w][kingslot]))
      cen = cen_wkc;

/* test black passive check */

  if (cen == cen_lgl)
    if ((curr_e.e_pasc == c_b) && SANAttack (c_w, plv[c_b][kingslot]))
      cen = cen_bkc;

/* test ep capture target */

  if (cen == cen_lgl)
    if (curr_e.e_epsq != sq_nil)
      if (curr_e.e_actc == c_w)
	{
	  if ((map_rank_sq (curr_e.e_epsq) != rank_6) ||
	      (gb.bv[curr_e.e_epsq + dv_3] != cp_bp))
	    cen = cen_ept;
	}
      else
	{
	  if ((map_rank_sq (curr_e.e_epsq) != rank_3) ||
	      (gb.bv[curr_e.e_epsq + dv_1] != cp_wp))
	    cen = cen_ept;
	};

  return (cen);
}

/*--> SANSameMove: determine if two moves are the same */
nonstatic
siT
SANSameMove (mptrT mptr0, mptrT mptr1)
{
  siT flag;

  if ((mptr0->m_tosq == mptr1->m_tosq) &&
      (mptr0->m_frsq == mptr1->m_frsq) &&
      (mptr0->m_scmv == mptr1->m_scmv) &&
      (mptr0->m_tocp == mptr1->m_tocp) &&
      (mptr0->m_frcp == mptr1->m_frcp))
    flag = 1;
  else
    flag = 0;

  return (flag);
}

/*--> SANFindMove: locate a move in the current move list */
nonstatic
mptrT
SANFindMove (mptrT mptr)
{
  mptrT rmptr, smptr;
  siT i;

  smptr = curr_g.g_base;
  rmptr = NULL;
  i = 0;

  while ((rmptr == NULL) && (i < curr_g.g_gmvc))
    if (SANSameMove (smptr, mptr))
      rmptr = smptr;
    else
      {
	smptr++;
	i++;
      };

  return (rmptr);
}

/*--> SANSingleMove: retrun pointer to single move (if exists) */
nonstatic
mptrT
SANSingleMove (void)
{
  mptrT mptr;

  if (curr_g.g_gmvc == 1)
    mptr = curr_g.g_base;
  else
    mptr = NULL;

  return (mptr);
}

/*--> SANMatingMove: retrun pointer to a mating move (if exists) */
nonstatic
mptrT
SANMatingMove (void)
{
  mptrT mptr, rmptr;
  siT i;

  mptr = NULL;
  rmptr = curr_g.g_base;
  i = 0;
  while ((mptr == NULL) && (i < curr_g.g_gmvc))
    if (rmptr->m_flag & mf_chmt)
      mptr = rmptr;
    else
      {
	rmptr++;
	i++;
      };

  return (mptr);
}

/*--> SANDrawingMove: retrun pointer to a drawing move (if exists) */
nonstatic
mptrT
SANDrawingMove (void)
{
  mptrT mptr, rmptr;
  siT i;

  mptr = NULL;
  rmptr = curr_g.g_base;
  i = 0;
  while ((mptr == NULL) && (i < curr_g.g_gmvc))
    if (rmptr->m_flag & mf_draw)
      mptr = rmptr;
    else
      {
	rmptr++;
	i++;
      };

  return (mptr);
}

/*<<< sanmsc.c: EOF */
