/*>>> sanmlm.c: SAN project move list management routines */

/* Revised: 1993.05.16 */

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

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

#include "sanatk.h"
#include "sangen.h"
#include "sanmer.h"
#include "sanmne.h"
#include "sanmlm.h"
#include "sanutl.h"

/*--> SANMLExec: execute the current move list */
nonstatic
void
SANMLExec (void)
{
  siT i;

  if (!(curr_g.g_flag & gf_exec))
    {
      curr_g.g_flag |= gf_exec;

      /* test and mark each move for legality and checking status */

      curr_g.g_curr = curr_g.g_base;
      for (i = 0; i < curr_g.g_gmvc; i++)
	{
	  SANExecute ();
	  SANRetract ();
	  curr_g.g_curr++;
	};
    };

  return;
}

/*--> SANMLPolice: remove illegal moves the current move list */
nonstatic
void
SANMLPolice (void)
{
  mptrT tptr;
  siT i, bust;
  mT t_m;

  if (!(curr_g.g_flag & gf_plcd))
    {
      curr_g.g_flag |= gf_plcd;
      SANMLExec ();

      /* move illegal moves to end of list */

      curr_g.g_curr = curr_g.g_base;
      bust = 0;
      i = 0;
      while (i < (curr_g.g_gmvc - bust))
	if (curr_g.g_curr->m_flag & mf_bust)
	  {
	    tptr = (curr_g.g_base + (curr_g.g_gmvc - 1)) - bust;
	    t_m = *curr_g.g_curr;
	    *curr_g.g_curr = *tptr;
	    *tptr = t_m;
	    bust++;
	  }
	else
	  {
	    curr_g.g_curr++;
	    i++;
	  };

      /* shrink */

      curr_g.g_gmvc -= bust;
    };

  return;
}

/*--> SANMLEnsurePolice: ensure generation, then police */
nonstatic
void
SANMLEnsurePolice (void)
{
  if (!(curr_g.g_flag & gf_full))
    SANGenFullPL ();
  SANMLPolice ();

  return;
}

/*--> SANMLDisambiguate: insert disambiguation flags in move list */
nonstatic
void
SANMLDisambiguate (void)
{
  siT i, j, tmc, rmc, fmc;
  mptrT mptr0, mptr1;
  pT p;
  rankT rank;
  fileT file;

  if (!(curr_g.g_flag & gf_dsam))
    {
      curr_g.g_flag |= gf_dsam;
      SANMLPolice ();

      /* it's magic */

      mptr0 = curr_g.g_base;
      for (i = 0; i < curr_g.g_gmvc; i++)
	{
	  /* the outer loop disambiguates a single move per cycle */

	  p = cv_p_cpv[mptr0->m_frcp];
	  if ((p != p_p) && (p != p_k))
	    {
	      rank = map_rank_sq (mptr0->m_frsq);
	      file = map_file_sq (mptr0->m_frsq);
	      tmc = rmc = fmc = 0;
	      mptr1 = curr_g.g_base;
	      for (j = 0; j < curr_g.g_gmvc; j++)
		{
		  /* the inner loop examines all possible sibling puns */

		  if ((i != j) && (mptr0->m_frcp == mptr1->m_frcp) &&
		      (mptr0->m_tosq == mptr1->m_tosq))
		    {
		      tmc++;
		      if (map_rank_sq (mptr1->m_frsq) == rank)
			rmc++;
		      if (map_file_sq (mptr1->m_frsq) == file)
			fmc++;
		    };
		  mptr1++;
		};

	      /* check pun count for outer loop move */

	      if (tmc > 0)
		{
		  /* file disambiguation has priority */

		  if ((rmc > 0) || ((rmc == 0) && (fmc == 0)))
		    mptr0->m_flag |= mf_sanf;

		  /* rank disambiguation may be needed */

		  if (fmc > 0)
		    mptr0->m_flag |= mf_sanr;
		};
	    };
	  mptr0++;
	};
    };

  return;
}

/*--> SANMLScanMate: scan current move list for mating moves */
nonstatic
void
SANMLScanMate (void)
{
  siT i, j, mate, draw, move;

  if (!(curr_g.g_flag & gf_mate))
    {
      curr_g.g_flag |= gf_mate;
      SANMLPolice ();

      /* scan */

      curr_g.g_curr = curr_g.g_base;
      for (i = 0; i < curr_g.g_gmvc; i++)
	{
	  SANExecute ();

	  /* now at next higher ply, generate psuedolegal set */

	  SANGenFullPL ();

	  /* try to find at least one legal move */

	  curr_g.g_curr = curr_g.g_base;
	  move = 0;
	  j = 0;
	  while (!move && (j < curr_g.g_gmvc))
	    {
	      SANExecute ();
	      SANRetract ();
	      if (!(curr_g.g_curr->m_flag & mf_bust))
		move = 1;
	      else
		{
		  curr_g.g_curr++;
		  j++;
		};
	    };

	  /* any second level moves detected? */

	  if (move != 0)
	    {
	      /* not a mate */

	      mate = draw = 0;
	    }
	  else
	    {
	      /* a mating move is detected */

	      if (SANAttack (curr_e.e_pasc, plv[curr_e.e_actc][kingslot]))
		{
		  mate = 1;
		  draw = 0;
		}
	      else
		{
		  draw = 1;
		  mate = 0;
		};
	    };

	  /* undo execution */

	  SANRetract ();

	  /* now back at lower ply */

	  if (mate)
	    curr_g.g_curr->m_flag |= mf_chmt;
	  else if (draw)
	    curr_g.g_curr->m_flag |= (mf_draw | mf_stmt);

	  /* next move */

	  curr_g.g_curr++;
	};
    };

  return;
}

/*<<< sanmlm.c: EOF */
