/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 * This file is part of SanKit -- A multiplatform set of C code
 * for reading and writing PGN formatted chess games. In addition
 * it can be used as an engine to determine in real time if proposed
 * moves are legal or not. It appears to generate near perfect PGN
 * from incorrectly formatted files.
 *
 * Copyright 1994 Steven J. Edwards All Rights Reserved.
 * Copyright 2009-2011 David Hoerl All Rights Reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*>>> sangen.c: SAN project move generation routines */

/* Revised: 1993.05.16 */

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

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

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

/* the generated move template */

static mT gm;

/*--> SANGenCaptPL: generate psuedolegal capture moves */
nonstatic
void SANGenCaptPL(void)
{
	siT i, n;
	dxT dx;
	dvT dv;
	xdvT xdv;
	xsqptrT xsqptr0, xsqptr1;
	fileT frfile;
	rankT frrank;

/* set up current generation items */

	if(an == 0) {
		curr_g.g_strt = 0;
	} else {
		curr_g.g_strt = av[an - 1].a_g.g_strt + av[an - 1].a_g.g_gmvc;
	}

	curr_g.g_curr = curr_g.g_base = &Tree[curr_g.g_strt];
	curr_g.g_gmvc = 0;
	curr_g.g_flag = gf_capt;

/* set the psuedoinvariant generated move template components */

	gm.m_scmv = scmv_reg;
	gm.m_eval = ev_bust;
	gm.m_flag = 0;
	gm.m_nag = 0;
	gm.m_nag = 0;
	gm.m_cmt = NULL;
	gm.m_rav = NULL;

/* look at each origin square of the active color */

	n = plnv[curr_e.e_actc];
	for(i = 0; i < n; i++) {
		/* get origin square and moving piece */

		gm.m_frcp = gb.bv[gm.m_frsq = plv[curr_e.e_actc][i]];

		/* generate moves for active color piece */

		xsqptr0 = &gxb.xbv[map_xsq_sq(gm.m_frsq)];
		switch(cv_p_cpv[gm.m_frcp]) {
		case p_p:
			/* pawn moves: a bit tricky; colors done separately */

			frfile = map_file_sq(gm.m_frsq);
			frrank = map_rank_sq(gm.m_frsq);
			if(curr_e.e_actc == c_w) {
				/* one square non-capture promote */

				gm.m_tocp = gb.bv[gm.m_tosq = gm.m_frsq + dv_1];
				if(gm.m_tocp == cp_v0) {
					if(frrank == rank_7) {
						/* promotion */

						for(gm.m_scmv = scmv_ppn;
							gm.m_scmv <= scmv_ppq; gm.m_scmv++)
						{
							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						}
						gm.m_scmv = scmv_reg;
					}
				}

				/* capture to left */

				if(frfile != file_a) {
					gm.m_tosq = gm.m_frsq + dv_5;
					gm.m_tocp = gb.bv[gm.m_tosq];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						if(frrank != rank_7) {
							/* non-promote */

							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						} else {
							/* promote */

							for(gm.m_scmv = scmv_ppn;
								gm.m_scmv <= scmv_ppq; gm.m_scmv++)
							{
								*curr_g.g_curr++ = gm;
								curr_g.g_gmvc++;
							}
							gm.m_scmv = scmv_reg;
						}
					}
				}

				/* capture to right */

				if(frfile != file_h) {
					gm.m_tosq = gm.m_frsq + dv_4;
					gm.m_tocp = gb.bv[gm.m_tosq];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						if(frrank != rank_7) {
							/* non-promote */

							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						} else {
							/* promote */

							for(gm.m_scmv = scmv_ppn;
								gm.m_scmv <= scmv_ppq; gm.m_scmv++)
							{
								*curr_g.g_curr++ = gm;
								curr_g.g_gmvc++;
							}
							gm.m_scmv = scmv_reg;
						}
					}
				}

				/* en passant */

				if((frrank == rank_5) && (curr_e.e_epsq != sq_nil)) {
					/* capture to left */

					if((frfile != file_a) &&
					   ((gm.m_tosq = gm.m_frsq + dv_5) == curr_e.e_epsq))
					{
						gm.m_tocp = cp_v0;
						gm.m_scmv = scmv_epc;
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
						gm.m_scmv = scmv_reg;
					}

					/* capture to right */

					if((frfile != file_h) &&
					   ((gm.m_tosq = gm.m_frsq + dv_4) == curr_e.e_epsq))
					{
						gm.m_tocp = cp_v0;
						gm.m_scmv = scmv_epc;
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
						gm.m_scmv = scmv_reg;
					}
				}
			} else {
				/* one square non-capture promote */

				gm.m_tocp = gb.bv[gm.m_tosq = gm.m_frsq + dv_3];
				if(gm.m_tocp == cp_v0) {
					if(frrank == rank_2) {
						/* promotion */

						for(gm.m_scmv = scmv_ppn;
							gm.m_scmv <= scmv_ppq; gm.m_scmv++)
						{
							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						}
						gm.m_scmv = scmv_reg;
					}
				}

				/* capture to left */

				if(frfile != file_a) {
					gm.m_tosq = gm.m_frsq + dv_6;
					gm.m_tocp = gb.bv[gm.m_tosq];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						if(frrank != rank_2) {
							/* non-promote */

							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						} else {
							/* promote */

							for(gm.m_scmv = scmv_ppn;
								gm.m_scmv <= scmv_ppq; gm.m_scmv++)
							{
								*curr_g.g_curr++ = gm;
								curr_g.g_gmvc++;
							}
							gm.m_scmv = scmv_reg;
						}
					}
				}

				/* capture to right */

				if(frfile != file_h) {
					gm.m_tosq = gm.m_frsq + dv_7;
					gm.m_tocp = gb.bv[gm.m_tosq];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						if(frrank != rank_2) {
							/* non-promote */

							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						} else {
							/* promote */

							for(gm.m_scmv = scmv_ppn;
								gm.m_scmv <= scmv_ppq; gm.m_scmv++)
							{
								*curr_g.g_curr++ = gm;
								curr_g.g_gmvc++;
							}
							gm.m_scmv = scmv_reg;
						}
					}
				}

				/* en passant */

				if((frrank == rank_4) && (curr_e.e_epsq != sq_nil)) {
					/* capture to left */

					if((frfile != file_a) &&
					   ((gm.m_tosq = gm.m_frsq + dv_6) == curr_e.e_epsq))
					{
						gm.m_tocp = cp_v0;
						gm.m_scmv = scmv_epc;
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
						gm.m_scmv = scmv_reg;
					}

					/* capture to right */

					if((frfile != file_h) &&
					   ((gm.m_tosq = gm.m_frsq + dv_7) == curr_e.e_epsq))
					{
						gm.m_tocp = cp_v0;
						gm.m_scmv = scmv_epc;
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
						gm.m_scmv = scmv_reg;
					}
				}
			}
			break;

		case p_n:
			/* knight moves: very simple */

			for(dx = dx_8; dx <= dx_f; dx++) {
				if(*(xsqptr0 + xdvv[dx]) == cp_v0) {
					gm.m_tocp = gb.bv[gm.m_tosq = gm.m_frsq + dvv[dx]];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
					}
				}
			}
			break;

		case p_b:
			/* bishop moves: diagonal sweeper */

			for(dx = dx_4; dx <= dx_7; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				gm.m_tosq = gm.m_frsq;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  ((gm.m_tocp = gb.bv[gm.m_tosq += dv]) == cp_v0))
				{
				}
				if((*xsqptr1 == cp_v0) &&
				   (cv_c_cpv[gm.m_tocp] == curr_e.e_pasc))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
			}
			break;

		case p_r:
			/* rook moves: orthogonal sweeper */

			for(dx = dx_0; dx <= dx_3; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				gm.m_tosq = gm.m_frsq;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  ((gm.m_tocp = gb.bv[gm.m_tosq += dv]) == cp_v0))
				{
				}
				if((*xsqptr1 == cp_v0) &&
				   (cv_c_cpv[gm.m_tocp] == curr_e.e_pasc))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
			}
			break;

		case p_q:
			/* queen moves: orthogonal and diagonal sweeper */

			for(dx = dx_0; dx <= dx_7; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				gm.m_tosq = gm.m_frsq;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  ((gm.m_tocp = gb.bv[gm.m_tosq += dv]) == cp_v0))
				{
				}
				if((*xsqptr1 == cp_v0) &&
				   (cv_c_cpv[gm.m_tocp] == curr_e.e_pasc))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
			}
			break;

		case p_k:
			/* king moves: one square adjacent captures */

			for(dx = dx_0; dx <= dx_7; dx++) {
				if(*(xsqptr0 + xdvv[dx]) == cp_v0) {
					gm.m_tocp = gb.bv[gm.m_tosq = gm.m_frsq + dvv[dx]];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
					}
				}
			}
			break;
		}
	}

/* reset the current pointer */

	curr_g.g_curr = curr_g.g_base;

	return;
}

/*--> SANGenFullPL: generate psuedolegal moves */
nonstatic
void SANGenFullPL(void)
{
	siT i, n;
	dxT dx;
	dvT dv;
	xdvT xdv;
	xsqptrT xsqptr0, xsqptr1;
	fileT frfile;
	rankT frrank;

/* set up current generation items */

	if(an == 0) {
		curr_g.g_strt = 0;
	} else {
		curr_g.g_strt = av[an - 1].a_g.g_strt + av[an - 1].a_g.g_gmvc;
	}

	curr_g.g_curr = curr_g.g_base = &Tree[curr_g.g_strt];
	curr_g.g_gmvc = 0;
	curr_g.g_flag = gf_full;

/* set the psuedoinvariant generated move template components */

	gm.m_scmv = scmv_reg;
	gm.m_eval = ev_bust;
	gm.m_flag = 0;
	gm.m_nag = 0;
	gm.m_cmt = NULL;
	gm.m_rav = NULL;

/* look at each origin square of the active color */

	n = plnv[curr_e.e_actc];
	for(i = 0; i < n; i++) {
		/* get origin square and moving piece */

		gm.m_frcp = gb.bv[gm.m_frsq = plv[curr_e.e_actc][i]];

		/* generate moves for active color piece */

		xsqptr0 = &gxb.xbv[map_xsq_sq(gm.m_frsq)];
		switch(cv_p_cpv[gm.m_frcp]) {
		case p_p:
			/* pawn moves: a bit tricky; colors done separately */

			frfile = map_file_sq(gm.m_frsq);
			frrank = map_rank_sq(gm.m_frsq);
			if(curr_e.e_actc == c_w) {
				/* one square non-capture */

				gm.m_tocp = gb.bv[gm.m_tosq = gm.m_frsq + dv_1];
				if(gm.m_tocp == cp_v0) {
					if(frrank != rank_7) {
						/* non-promotion */

						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
					} else {
						/* promotion */

						for(gm.m_scmv = scmv_ppn;
							gm.m_scmv <= scmv_ppq; gm.m_scmv++)
						{
							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						}
						gm.m_scmv = scmv_reg;
					}
				}

				/* two squares forward */

				if((frrank == rank_2) &&
				   (gb.bv[gm.m_frsq + dv_1] == cp_v0) &&
				   (gb.bv[gm.m_frsq + (2 * dv_1)] == cp_v0))
				{
					gm.m_tosq = gm.m_frsq + (2 * dv_1);
					gm.m_tocp = cp_v0;
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}

				/* capture to left */

				if(frfile != file_a) {
					gm.m_tosq = gm.m_frsq + dv_5;
					gm.m_tocp = gb.bv[gm.m_tosq];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						if(frrank != rank_7) {
							/* non-promote */

							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						} else {
							/* promote */

							for(gm.m_scmv = scmv_ppn;
								gm.m_scmv <= scmv_ppq; gm.m_scmv++)
							{
								*curr_g.g_curr++ = gm;
								curr_g.g_gmvc++;
							}
							gm.m_scmv = scmv_reg;
						}
					}
				}

				/* capture to right */

				if(frfile != file_h) {
					gm.m_tosq = gm.m_frsq + dv_4;
					gm.m_tocp = gb.bv[gm.m_tosq];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						if(frrank != rank_7) {
							/* non-promote */

							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						} else {
							/* promote */

							for(gm.m_scmv = scmv_ppn;
								gm.m_scmv <= scmv_ppq; gm.m_scmv++)
							{
								*curr_g.g_curr++ = gm;
								curr_g.g_gmvc++;
							}
							gm.m_scmv = scmv_reg;
						}
					}
				}

				/* en passant */

				if((frrank == rank_5) && (curr_e.e_epsq != sq_nil)) {
					/* capture to left */

					if((frfile != file_a) &&
					   ((gm.m_tosq = gm.m_frsq + dv_5) == curr_e.e_epsq))
					{
						gm.m_tocp = cp_v0;
						gm.m_scmv = scmv_epc;
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
						gm.m_scmv = scmv_reg;
					}

					/* capture to right */

					if((frfile != file_h) &&
					   ((gm.m_tosq = gm.m_frsq + dv_4) == curr_e.e_epsq))
					{
						gm.m_tocp = cp_v0;
						gm.m_scmv = scmv_epc;
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
						gm.m_scmv = scmv_reg;
					}
				}
			} else {
				/* one square non-capture */

				gm.m_tocp = gb.bv[gm.m_tosq = gm.m_frsq + dv_3];
				if(gm.m_tocp == cp_v0) {
					if(frrank != rank_2) {
						/* non-promotion */

						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
					} else {
						/* promotion */

						for(gm.m_scmv = scmv_ppn;
							gm.m_scmv <= scmv_ppq; gm.m_scmv++)
						{
							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						}
						gm.m_scmv = scmv_reg;
					}
				}

				/* two squares forward */

				if((frrank == rank_7) &&
				   (gb.bv[gm.m_frsq + dv_3] == cp_v0) &&
				   (gb.bv[gm.m_frsq + (2 * dv_3)] == cp_v0))
				{
					gm.m_tosq = gm.m_frsq + (2 * dv_3);
					gm.m_tocp = cp_v0;
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}

				/* capture to left */

				if(frfile != file_a) {
					gm.m_tosq = gm.m_frsq + dv_6;
					gm.m_tocp = gb.bv[gm.m_tosq];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						if(frrank != rank_2) {
							/* non-promote */

							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						} else {
							/* promote */

							for(gm.m_scmv = scmv_ppn;
								gm.m_scmv <= scmv_ppq; gm.m_scmv++)
							{
								*curr_g.g_curr++ = gm;
								curr_g.g_gmvc++;
							}
							gm.m_scmv = scmv_reg;
						}
					}
				}

				/* capture to right */

				if(frfile != file_h) {
					gm.m_tosq = gm.m_frsq + dv_7;
					gm.m_tocp = gb.bv[gm.m_tosq];
					if(cv_c_cpv[gm.m_tocp] == curr_e.e_pasc) {
						if(frrank != rank_2) {
							/* non-promote */

							*curr_g.g_curr++ = gm;
							curr_g.g_gmvc++;
						} else {
							/* promote */

							for(gm.m_scmv = scmv_ppn;
								gm.m_scmv <= scmv_ppq; gm.m_scmv++)
							{
								*curr_g.g_curr++ = gm;
								curr_g.g_gmvc++;
							}
							gm.m_scmv = scmv_reg;
						}
					}
				}

				/* en passant */

				if((frrank == rank_4) && (curr_e.e_epsq != sq_nil)) {
					/* capture to left */

					if((frfile != file_a) &&
					   ((gm.m_tosq = gm.m_frsq + dv_6) == curr_e.e_epsq))
					{
						gm.m_tocp = cp_v0;
						gm.m_scmv = scmv_epc;
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
						gm.m_scmv = scmv_reg;
					}

					/* capture to right */

					if((frfile != file_h) &&
					   ((gm.m_tosq = gm.m_frsq + dv_7) == curr_e.e_epsq))
					{
						gm.m_tocp = cp_v0;
						gm.m_scmv = scmv_epc;
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
						gm.m_scmv = scmv_reg;
					}
				}
			}
			break;

		case p_n:
			/* knight moves: very simple */

			for(dx = dx_8; dx <= dx_f; dx++) {
				if(*(xsqptr0 + xdvv[dx]) == cp_v0) {
					gm.m_tocp = gb.bv[gm.m_tosq = gm.m_frsq + dvv[dx]];
					if(cv_c_cpv[gm.m_tocp] != curr_e.e_actc) {
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
					}
				}
			}
			break;

		case p_b:
			/* bishop moves: diagonal sweeper */

			for(dx = dx_4; dx <= dx_7; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				gm.m_tosq = gm.m_frsq;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  ((gm.m_tocp = gb.bv[gm.m_tosq += dv]) == cp_v0))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
				if((*xsqptr1 == cp_v0) &&
				   (cv_c_cpv[gm.m_tocp] == curr_e.e_pasc))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
			}
			break;

		case p_r:
			/* rook moves: orthogonal sweeper */

			for(dx = dx_0; dx <= dx_3; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				gm.m_tosq = gm.m_frsq;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  ((gm.m_tocp = gb.bv[gm.m_tosq += dv]) == cp_v0))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
				if((*xsqptr1 == cp_v0) &&
				   (cv_c_cpv[gm.m_tocp] == curr_e.e_pasc))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
			}
			break;

		case p_q:
			/* queen moves: orthogonal and diagonal sweeper */

			for(dx = dx_0; dx <= dx_7; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				gm.m_tosq = gm.m_frsq;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  ((gm.m_tocp = gb.bv[gm.m_tosq += dv]) == cp_v0))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
				if((*xsqptr1 == cp_v0) &&
				   (cv_c_cpv[gm.m_tocp] == curr_e.e_pasc))
				{
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
				}
			}
			break;

		case p_k:
			/* king moves: one square adjacent regular */

			for(dx = dx_0; dx <= dx_7; dx++) {
				if(*(xsqptr0 + xdvv[dx]) == cp_v0) {
					gm.m_tocp = gb.bv[gm.m_tosq = gm.m_frsq + dvv[dx]];
					if(cv_c_cpv[gm.m_tocp] != curr_e.e_actc) {
						*curr_g.g_curr++ = gm;
						curr_g.g_gmvc++;
					}
				}
			}

			/* castling; process according to active color */

			if(curr_e.e_actc == c_w) {
				if((curr_e.e_cast & cast_wk) && !SANBlackAttacks(sq_e1) &&
				   (gb.bv[sq_f1] == cp_v0) && !SANBlackAttacks(sq_f1) &&
				   (gb.bv[sq_g1] == cp_v0) && !SANBlackAttacks(sq_g1))
				{
					gm.m_tosq = sq_g1;
					gm.m_tocp = cp_v0;
					gm.m_scmv = scmv_cks;
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
					gm.m_scmv = scmv_reg;
				}

				if((curr_e.e_cast & cast_wq) && !SANBlackAttacks(sq_e1) &&
				   (gb.bv[sq_d1] == cp_v0) && !SANBlackAttacks(sq_d1) &&
				   (gb.bv[sq_c1] == cp_v0) && !SANBlackAttacks(sq_c1) &&
				   (gb.bv[sq_b1] == cp_v0))
				{
					gm.m_tosq = sq_c1;
					gm.m_tocp = cp_v0;
					gm.m_scmv = scmv_cqs;
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
					gm.m_scmv = scmv_reg;
				}
			} else {
				if((curr_e.e_cast & cast_bk) && !SANWhiteAttacks(sq_e8) &&
				   (gb.bv[sq_f8] == cp_v0) && !SANWhiteAttacks(sq_f8) &&
				   (gb.bv[sq_g8] == cp_v0) && !SANWhiteAttacks(sq_g8))
				{
					gm.m_tosq = sq_g8;
					gm.m_tocp = cp_v0;
					gm.m_scmv = scmv_cks;
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
					gm.m_scmv = scmv_reg;
				}

				if((curr_e.e_cast & cast_bq) && !SANWhiteAttacks(sq_e8) &&
				   (gb.bv[sq_d8] == cp_v0) && !SANWhiteAttacks(sq_d8) &&
				   (gb.bv[sq_c8] == cp_v0) && !SANWhiteAttacks(sq_c8) &&
				   (gb.bv[sq_b8] == cp_v0))
				{
					gm.m_tosq = sq_c8;
					gm.m_tocp = cp_v0;
					gm.m_scmv = scmv_cqs;
					*curr_g.g_curr++ = gm;
					curr_g.g_gmvc++;
					gm.m_scmv = scmv_reg;
				}
			}
			break;
		}
	}

/* reset the current pointer */

	curr_g.g_curr = curr_g.g_base;

	return;
}

/*--> SANGenClean: generate move list with first level processing */
static
void SANGenClean(void)
{
/* basic psuedolegal generation */

	SANGenFullPL();

/* set legality flags, remove illegal moves, and disambiguate */

	SANMLExec();
	SANMLPolice();
	SANMLDisambiguate();

	return;
}

/*--> SANGenMoves: generate ordered legal moves */
nonstatic
void SANGenMoves(void)
{
/* perform basic first level generation */

	SANGenClean();

/* handle two ply draw and checkmate detection */

	SANMLScanMate();

/* sort the result by SAN alphabetically for canonical order */

	SANSortSAN();

	return;
}

/*<<< sangen.c: EOF */
