/*>>> sanmer.c: SAN project move execution and retraction routines */

/* Revised: 1993.09.05 */

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

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

#include "sanatk.h"
#include "sangen.h"
#include "sanhsh.h"
#include "sanmer.h"
#include "sanmsc.h"
#include "sanutl.h"

/*--> SANExecute: execute the current move */
nonstatic
void
SANExecute (void)
{
  mptrT mptr;
  sqT pcsq;
  cpT pccp, ppcp;

/* test for overflow */

  if (an == (aL - 1))
    SANFatal ("SANExecute: overflow");

/* save old environment and generation records */

  av[an].a_e = curr_e;
  av[an].a_g = curr_g;

/* set the move pointer */

  mptr = curr_g.g_curr;

/* set the legality tested flag */

  mptr->m_flag |= mf_exec;

/* process according to move case */

  switch (mptr->m_scmv)
    {
    case scmv_reg:
      if (curr_e.e_actc == c_w)
	{
	  if (mptr->m_tocp != cp_v0)
	    {
	      cpmv[c_b] -= valcpv[mptr->m_tocp];
	      SANSubPiece (mptr->m_tosq);
	    };
	  plv[c_w][biv[mptr->m_tosq] = biv[mptr->m_frsq]] = mptr->m_tosq;
	}
      else
	{
	  if (mptr->m_tocp != cp_v0)
	    {
	      cpmv[c_w] -= valcpv[mptr->m_tocp];
	      SANSubPiece (mptr->m_tosq);
	    };
	  plv[c_b][biv[mptr->m_tosq] = biv[mptr->m_frsq]] = mptr->m_tosq;
	};
      gb.bv[mptr->m_frsq] = cp_v0;
      gb.bv[mptr->m_tosq] = mptr->m_frcp;
      SANHashColorPieceSqSq (mptr->m_frcp, mptr->m_frsq, mptr->m_tosq);
      if (mptr->m_tocp != cp_v0)
	SANHashColorPieceSq (mptr->m_tocp, mptr->m_tosq);
      break;

    case scmv_epc:
      cpmv[curr_e.e_pasc] -= val_p;
      if (curr_e.e_actc == c_w)
	{
	  pccp = cp_bp;
	  pcsq = mptr->m_tosq + dv_3;
	}
      else
	{
	  pccp = cp_wp;
	  pcsq = mptr->m_tosq + dv_1;
	};
      SANSubPiece (pcsq);
      plv[curr_e.e_actc][biv[mptr->m_tosq] = biv[mptr->m_frsq]] =
	mptr->m_tosq;
      gb.bv[mptr->m_frsq] = cp_v0;
      gb.bv[mptr->m_tosq] = mptr->m_frcp;
      gb.bv[pcsq] = cp_v0;

      SANHashColorPieceSqSq (mptr->m_frcp, mptr->m_frsq, mptr->m_tosq);
      SANHashColorPieceSq (pccp, pcsq);
      break;

    case scmv_cks:
      SANHashColorPieceSqSq (mptr->m_frcp, mptr->m_frsq, mptr->m_tosq);
      if (curr_e.e_actc == c_w)
	{
	  gb.bv[sq_e1] = cp_v0;
	  gb.bv[sq_g1] = cp_wk;
	  gb.bv[sq_h1] = cp_v0;
	  gb.bv[sq_f1] = cp_wr;
	  biv[plv[c_w][kingslot] = sq_g1] = kingslot;
	  plv[c_w][biv[sq_f1] = biv[sq_h1]] = sq_f1;
	  SANHashColorPieceSqSq (cp_wr, sq_h1, sq_f1);
	}
      else
	{
	  gb.bv[sq_e8] = cp_v0;
	  gb.bv[sq_g8] = cp_bk;
	  gb.bv[sq_h8] = cp_v0;
	  gb.bv[sq_f8] = cp_br;
	  biv[plv[c_b][kingslot] = sq_g8] = kingslot;
	  plv[c_b][biv[sq_f8] = biv[sq_h8]] = sq_f8;
	  SANHashColorPieceSqSq (cp_br, sq_h8, sq_f8);
	};
      break;

    case scmv_cqs:
      SANHashColorPieceSqSq (mptr->m_frcp, mptr->m_frsq, mptr->m_tosq);
      if (curr_e.e_actc == c_w)
	{
	  gb.bv[sq_e1] = cp_v0;
	  gb.bv[sq_c1] = cp_wk;
	  gb.bv[sq_a1] = cp_v0;
	  gb.bv[sq_d1] = cp_wr;
	  biv[plv[c_w][kingslot] = sq_c1] = kingslot;
	  plv[c_w][biv[sq_d1] = biv[sq_a1]] = sq_d1;
	  SANHashColorPieceSqSq (cp_wr, sq_a1, sq_d1);
	}
      else
	{
	  gb.bv[sq_e8] = cp_v0;
	  gb.bv[sq_c8] = cp_bk;
	  gb.bv[sq_a8] = cp_v0;
	  gb.bv[sq_d8] = cp_br;
	  biv[plv[c_b][kingslot] = sq_c8] = kingslot;
	  plv[c_b][biv[sq_d8] = biv[sq_a8]] = sq_d8;
	  SANHashColorPieceSqSq (cp_br, sq_a8, sq_d8);
	};
      break;

    case scmv_ppn:
      SANHashColorPieceSq (mptr->m_frcp, mptr->m_frsq);
      if (curr_e.e_actc == c_w)
	ppcp = cp_wn;
      else
	ppcp = cp_bn;
      SANHashColorPieceSq (ppcp, mptr->m_tosq);
      cpmv[curr_e.e_actc] += val_n - val_p;
      if (mptr->m_tocp != cp_v0)
	{
	  SANSubPiece (mptr->m_tosq);
	  SANHashColorPieceSq (mptr->m_tocp, mptr->m_tosq);
	  cpmv[curr_e.e_pasc] -= valcpv[mptr->m_tocp];
	};
      gb.bv[mptr->m_frsq] = cp_v0;
      gb.bv[mptr->m_tosq] = ppcp;
      plv[curr_e.e_actc][biv[mptr->m_tosq] = biv[mptr->m_frsq]] =
	mptr->m_tosq;
      break;

    case scmv_ppb:
      SANHashColorPieceSq (mptr->m_frcp, mptr->m_frsq);
      if (curr_e.e_actc == c_w)
	ppcp = cp_wb;
      else
	ppcp = cp_bb;
      SANHashColorPieceSq (ppcp, mptr->m_tosq);
      cpmv[curr_e.e_actc] += val_b - val_p;
      if (mptr->m_tocp != cp_v0)
	{
	  SANSubPiece (mptr->m_tosq);
	  SANHashColorPieceSq (mptr->m_tocp, mptr->m_tosq);
	  cpmv[curr_e.e_pasc] -= valcpv[mptr->m_tocp];
	};
      gb.bv[mptr->m_frsq] = cp_v0;
      gb.bv[mptr->m_tosq] = ppcp;
      plv[curr_e.e_actc][biv[mptr->m_tosq] = biv[mptr->m_frsq]] =
	mptr->m_tosq;
      break;

    case scmv_ppr:
      SANHashColorPieceSq (mptr->m_frcp, mptr->m_frsq);
      if (curr_e.e_actc == c_w)
	ppcp = cp_wr;
      else
	ppcp = cp_br;
      SANHashColorPieceSq (ppcp, mptr->m_tosq);
      cpmv[curr_e.e_actc] += val_r - val_p;
      if (mptr->m_tocp != cp_v0)
	{
	  SANSubPiece (mptr->m_tosq);
	  SANHashColorPieceSq (mptr->m_tocp, mptr->m_tosq);
	  cpmv[curr_e.e_pasc] -= valcpv[mptr->m_tocp];
	};
      gb.bv[mptr->m_frsq] = cp_v0;
      gb.bv[mptr->m_tosq] = ppcp;
      plv[curr_e.e_actc][biv[mptr->m_tosq] = biv[mptr->m_frsq]] =
	mptr->m_tosq;
      break;

    case scmv_ppq:
      SANHashColorPieceSq (mptr->m_frcp, mptr->m_frsq);
      if (curr_e.e_actc == c_w)
	ppcp = cp_wq;
      else
	ppcp = cp_bq;
      SANHashColorPieceSq (ppcp, mptr->m_tosq);
      cpmv[curr_e.e_actc] += val_q - val_p;
      if (mptr->m_tocp != cp_v0)
	{
	  SANSubPiece (mptr->m_tosq);
	  SANHashColorPieceSq (mptr->m_tocp, mptr->m_tosq);
	  cpmv[curr_e.e_pasc] -= valcpv[mptr->m_tocp];
	};
      gb.bv[mptr->m_frsq] = cp_v0;
      gb.bv[mptr->m_tosq] = ppcp;
      plv[curr_e.e_actc][biv[mptr->m_tosq] = biv[mptr->m_frsq]] =
	mptr->m_tosq;
      break;
    };

/* set values for updated environment record: colors */

  curr_e.e_actc = inv_cv[curr_e.e_actc];
  curr_e.e_pasc = inv_cv[curr_e.e_pasc];

/* set values for updated environment record: castling */

  if (curr_e.e_cast != 0)
    {
      if (curr_e.e_cast & cast_wk)
	if ((mptr->m_frsq == sq_e1) || (mptr->m_frsq == sq_h1) ||
	    (mptr->m_tosq == sq_h1))
	  {
	    curr_e.e_cast &= ~cast_wk;
	    SANHashCastlingAvailability (cai_wk);
	  };

      if (curr_e.e_cast & cast_wq)
	if ((mptr->m_frsq == sq_e1) || (mptr->m_frsq == sq_a1) ||
	    (mptr->m_tosq == sq_a1))
	  {
	    curr_e.e_cast &= ~cast_wq;
	    SANHashCastlingAvailability (cai_wq);
	  };

      if (curr_e.e_cast & cast_bk)
	if ((mptr->m_frsq == sq_e8) || (mptr->m_frsq == sq_h8) ||
	    (mptr->m_tosq == sq_h8))
	  {
	    curr_e.e_cast &= ~cast_bk;
	    SANHashCastlingAvailability (cai_bk);
	  };

      if (curr_e.e_cast & cast_bq)
	if ((mptr->m_frsq == sq_e8) || (mptr->m_frsq == sq_a8) ||
	    (mptr->m_tosq == sq_a8))
	  {
	    curr_e.e_cast &= ~cast_bq;
	    SANHashCastlingAvailability (cai_bq);
	  };
    };

/* set values for updated environment record: en passant */

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

  if (curr_e.e_actc == c_b)
    if ((mptr->m_frcp == cp_wp) &&
	(map_rank_sq (mptr->m_frsq) == rank_2) &&
	(map_rank_sq (mptr->m_tosq) == rank_4))
      {
	curr_e.e_epsq = mptr->m_frsq + dv_1;
	SANHashEnPassantTargetFile ();
      }
    else
      curr_e.e_epsq = sq_nil;
  else if ((mptr->m_frcp == cp_bp) &&
	   (map_rank_sq (mptr->m_frsq) == rank_7) &&
	   (map_rank_sq (mptr->m_tosq) == rank_5))
    {
      curr_e.e_epsq = mptr->m_frsq + dv_3;
      SANHashEnPassantTargetFile ();
    }
  else
    curr_e.e_epsq = sq_nil;

/* set values for updated environment record: halfmove clock */

  if ((mptr->m_tocp != cp_v0) || (cv_p_cpv[mptr->m_frcp] == p_p))
    curr_e.e_hmvc = 0;
  else
    curr_e.e_hmvc++;

/* set move number + check/bust flags according to active color  */

  if (curr_e.e_actc == c_b)
    {
      if (SANBlackInCheck ())
	mptr->m_flag |= mf_chec;
      if (SANWhiteInCheck ())
	mptr->m_flag |= mf_bust;
    }
  else
    {
      curr_e.e_fmvn++;
      if (SANWhiteInCheck ())
	mptr->m_flag |= mf_chec;
      if (SANBlackInCheck ())
	mptr->m_flag |= mf_bust;
    };

/* update the generation information */

  curr_g.g_flag = 0;

/* increment ply */

  an++;

  return;
}

/*--> SANRetract: retract the previous move */
nonstatic
void
SANRetract (void)
{
  mptrT mptr;

/* decrement ply */

  an--;

/* restore the current environment and generation */

  curr_e = av[an].a_e;
  curr_g = av[an].a_g;

/* set the move pointer */

  mptr = curr_g.g_curr;

/* process by move case */

  switch (mptr->m_scmv)
    {
    case scmv_reg:
      gb.bv[mptr->m_tosq] = mptr->m_tocp;
      gb.bv[mptr->m_frsq] = mptr->m_frcp;
      if (curr_e.e_actc == c_w)
	{
	  plv[c_w][biv[mptr->m_frsq] = biv[mptr->m_tosq]] = mptr->m_frsq;
	  if (mptr->m_tocp != cp_v0)
	    {
	      SANAddPiece (mptr->m_tosq);
	      cpmv[c_b] += valcpv[mptr->m_tocp];
	    };
	}
      else
	{
	  plv[c_b][biv[mptr->m_frsq] = biv[mptr->m_tosq]] = mptr->m_frsq;
	  if (mptr->m_tocp != cp_v0)
	    {
	      SANAddPiece (mptr->m_tosq);
	      cpmv[c_w] += valcpv[mptr->m_tocp];
	    };
	};
      break;

    case scmv_epc:
      gb.bv[mptr->m_tosq] = cp_v0;
      gb.bv[mptr->m_frsq] = mptr->m_frcp;
      if (curr_e.e_actc == c_w)
	gb.bv[mptr->m_tosq + dv_3] = cp_bp;
      else
	gb.bv[mptr->m_tosq + dv_1] = cp_wp;
      if (curr_e.e_actc == c_w)
	SANAddPiece (mptr->m_tosq + dv_3);
      else
	SANAddPiece (mptr->m_tosq + dv_1);
      plv[curr_e.e_actc][biv[mptr->m_frsq] = biv[mptr->m_tosq]] =
	mptr->m_frsq;
      cpmv[curr_e.e_pasc] += val_p;
      break;

    case scmv_cks:
      if (curr_e.e_actc == c_w)
	{
	  gb.bv[sq_g1] = cp_v0;
	  gb.bv[sq_e1] = cp_wk;
	  gb.bv[sq_f1] = cp_v0;
	  gb.bv[sq_h1] = cp_wr;
	  biv[plv[c_w][kingslot] = sq_e1] = kingslot;
	  plv[c_w][biv[sq_h1] = biv[sq_f1]] = sq_h1;
	}
      else
	{
	  gb.bv[sq_g8] = cp_v0;
	  gb.bv[sq_e8] = cp_bk;
	  gb.bv[sq_f8] = cp_v0;
	  gb.bv[sq_h8] = cp_br;
	  biv[plv[c_b][kingslot] = sq_e8] = kingslot;
	  plv[c_b][biv[sq_h8] = biv[sq_f8]] = sq_h8;
	}
      break;

    case scmv_cqs:
      if (curr_e.e_actc == c_w)
	{
	  gb.bv[sq_c1] = cp_v0;
	  gb.bv[sq_e1] = cp_wk;
	  gb.bv[sq_d1] = cp_v0;
	  gb.bv[sq_a1] = cp_wr;
	  biv[plv[c_w][kingslot] = sq_e1] = kingslot;
	  plv[c_w][biv[sq_a1] = biv[sq_d1]] = sq_a1;
	}
      else
	{
	  gb.bv[sq_c8] = cp_v0;
	  gb.bv[sq_e8] = cp_bk;
	  gb.bv[sq_d8] = cp_v0;
	  gb.bv[sq_a8] = cp_br;
	  biv[plv[c_b][kingslot] = sq_e8] = kingslot;
	  plv[c_b][biv[sq_a8] = biv[sq_d8]] = sq_a8;
	};
      break;

    case scmv_ppn:
      cpmv[curr_e.e_actc] -= val_n - val_p;
      plv[curr_e.e_actc][biv[mptr->m_frsq] = biv[mptr->m_tosq]] =
	mptr->m_frsq;
      gb.bv[mptr->m_tosq] = mptr->m_tocp;
      gb.bv[mptr->m_frsq] = mptr->m_frcp;
      if (mptr->m_tocp != cp_v0)
	{
	  SANAddPiece (mptr->m_tosq);
	  cpmv[curr_e.e_pasc] += valcpv[mptr->m_tocp];
	};
      break;

    case scmv_ppb:
      cpmv[curr_e.e_actc] -= val_b - val_p;
      plv[curr_e.e_actc][biv[mptr->m_frsq] = biv[mptr->m_tosq]] =
	mptr->m_frsq;
      gb.bv[mptr->m_tosq] = mptr->m_tocp;
      gb.bv[mptr->m_frsq] = mptr->m_frcp;
      if (mptr->m_tocp != cp_v0)
	{
	  SANAddPiece (mptr->m_tosq);
	  cpmv[curr_e.e_pasc] += valcpv[mptr->m_tocp];
	};
      break;

    case scmv_ppr:
      cpmv[curr_e.e_actc] -= val_r - val_p;
      plv[curr_e.e_actc][biv[mptr->m_frsq] = biv[mptr->m_tosq]] =
	mptr->m_frsq;
      gb.bv[mptr->m_tosq] = mptr->m_tocp;
      gb.bv[mptr->m_frsq] = mptr->m_frcp;
      if (mptr->m_tocp != cp_v0)
	{
	  SANAddPiece (mptr->m_tosq);
	  cpmv[curr_e.e_pasc] += valcpv[mptr->m_tocp];
	};
      break;

    case scmv_ppq:
      cpmv[curr_e.e_actc] -= val_q - val_p;
      plv[curr_e.e_actc][biv[mptr->m_frsq] = biv[mptr->m_tosq]] =
	mptr->m_frsq;
      gb.bv[mptr->m_tosq] = mptr->m_tocp;
      gb.bv[mptr->m_frsq] = mptr->m_frcp;
      if (mptr->m_tocp != cp_v0)
	{
	  SANAddPiece (mptr->m_tosq);
	  cpmv[curr_e.e_pasc] += valcpv[mptr->m_tocp];
	};
      break;
    };

  return;
}

/*<<< sanmer.c: EOF */
