/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 * 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.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*>>> sanmnd.c: SAN project move notation decode routines */

/* Revised: 1993.04.10 */

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

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

#include "sanmnd.h"
#include "sanmne.h"

/*--> SANDecodeBump: increment a style vector and return overflow */
static
siT SANDecodeBump(ssavT ssav, ssavT bssav)
{
	siT flag;
	ssaT ssa;

	flag = 1;
	ssa = 0;
	while(flag && (ssa < ssaL)) {
		flag = 0;
		ssav[ssa]++;
		if(ssav[ssa] == bssav[ssa]) {
			flag = 1;
			ssav[ssa] = 0;
		}
		ssa++;
	}

	return flag;
}

/*--> SANDecodeFlex: locate a move from SAN (flexible interpretation) */
static
mptrT SANDecodeFlex(sanT san)
{
	mptrT mptr;
	ssavT ssav, bssav;
	siT i, flag;
	mptrT rmptr;
	sanT lcsan, rsan;


/* set default return value */

	mptr = NULL;

/* set minimal upper bounds */

	for(i = 0; i < ssaL; i++) {
		bssav[i] = 1;
	}

/* scan for upper bound conditions */

// DFH printf("gmvc=%d\n", curr_g.g_gmvc);

	rmptr = curr_g.g_base;
	for(i = 0; i < curr_g.g_gmvc; i++) {
		/* letter case */

		bssav[ssa_case] = 2;

		/* capturing */

		if((rmptr->m_tocp != cp_v0) || (rmptr->m_scmv == scmv_epc)) {
			bssav[ssa_capt] = 5;
		}

		/* checking */

		if(rmptr->m_flag & mf_chec) {
			bssav[ssa_chec] = 3;
		}

		/* castling */

		if((rmptr->m_scmv == scmv_cks) || (rmptr->m_scmv == scmv_cqs)) {
			bssav[ssa_cast] = 5;
		}

		/* promoting */

		if((rmptr->m_scmv == scmv_ppn) || (rmptr->m_scmv == scmv_ppb) ||
		   (rmptr->m_scmv == scmv_ppr) || (rmptr->m_scmv == scmv_ppq))
		{
			bssav[ssa_prom] = 4;
		}

		/* pawn destination target */

		if(cv_p_cpv[rmptr->m_frcp] == p_p) {
			bssav[ssa_ptar] = 2;
		}

		/* checkmating */

		if(rmptr->m_flag & mf_chmt) {
			bssav[ssa_chmt] = 4;
		}

		/* en passant capturing */

		if(rmptr->m_scmv == scmv_epc) {
			bssav[ssa_epct] = 2;
		}

		/* drawing */

		if(rmptr->m_flag & mf_draw) {
			bssav[ssa_draw] = 2;
		}

		/* moving (non-capturing) */

		if(optnv[optn_emde] && (rmptr->m_tocp == cp_v0) &&
		   (rmptr->m_scmv != scmv_epc))
		{
			bssav[ssa_move] = 2;
		}

		/* extra disambiguation: file */

		if(optnv[optn_emde] && !(rmptr->m_flag & mf_sanf)) {
			bssav[ssa_edcf] = 2;
		}

		/* extra disambiguation: rank */

		if(optnv[optn_emde] && !(rmptr->m_flag & mf_sanr)) {
			bssav[ssa_edcr] = 2;
		}

		rmptr++;
	}

/* make a lower case copy of the input */

	for(i = 0; i < sanL; i++) {
		char c = map_lower(san[i]);
		lcsan[i] = (c == '!' || c == '?') ? '\0' : c;
	}

/* initialize the index style vector */

	for(i = 0; i < ssaL; i++) {
		ssav[i] = 0;
	}

/* search */

	flag = 0;
	while(!flag && (mptr == NULL)) {
		rmptr = curr_g.g_base;
		i = 0;

		/* scan candidate moves */

		while((mptr == NULL) && (i < curr_g.g_gmvc)) {
			/* encode the current style version of a candidate */
			SANEncodeAux(rmptr, rsan, ssav);
#if 0	// DFH
			static mT err_mpt;
			memcpy(&err_mpt, rmptr, sizeof(err_mpt));

			printf("MPTR[%d:%d %s]: flag=%2.2x from=%c%c to=%c%c fr_cp=%x to_cp=%x special=%x eval=%x nag=%x\n", i, curr_g.g_gmvc, rsan,
				rmptr->m_flag,
				map_file_sq(rmptr->m_frsq) + 'a',
				map_rank_sq(rmptr->m_frsq) + '1',
				map_file_sq(rmptr->m_tosq) + 'a',
				map_rank_sq(rmptr->m_tosq) + '1',
				rmptr->m_frcp,
				rmptr->m_tocp,
				rmptr->m_scmv,
				rmptr->m_eval,
				rmptr->m_nag
				);
#endif
			/* select either original or lower case comparison */

			if(ssav[ssa_case] == 0) {
				if(strcmp(san, rsan) == 0) {
					mptr = rmptr;
				}
			} else {
				if(strcmp(lcsan, rsan) == 0) {
					mptr = rmptr;
				}
			}

			/* next candidate */

			rmptr++;
			i++;
		}

		/* update the overflow termination flag	*/

		flag = SANDecodeBump(ssav, bssav);
	}
#if 0	// DFH
	printf("FOUND MPR %s mptr=%x\n", san, (unsigned int)mptr);
	if(!mptr) {
		mptr = &err_mpt;
		mptr->m_flag = mf_exec;
		mptr->m_frsq = (01 << 3) || (04);
		mptr->m_tosq = (03 << 3) || (04);
		mptr->m_frcp = 0;
		mptr->m_tocp = 0xc;
		mptr->m_scmv = 0;
		mptr->m_eval = ev_bust;
		mptr->m_nag  = 0;
	}
#endif

	return mptr;
}

/*--> SANDecode: locate a move from SAN (strict interpretation) */
static
mptrT SANDecode(sanT san)
{
	mptrT mptr;
	mptrT rmptr;
	sanT rsan;
	siT i;

/* set default return value */

	mptr = NULL;

/* assume current moveset properly generated */

	rmptr = curr_g.g_base;
	i = 0;

/* search */

//printf("SanDecode: %s i=%d final=%d\n", san, i, curr_g.g_gmvc);
	while((mptr == NULL) && (i < curr_g.g_gmvc)) {
		SANEncode(rmptr, rsan);
		//printf("  %s i=%d final=%d rsan=%s\n", san, i, curr_g.g_gmvc, rsan);
		if(strcmp(san, rsan) == 0) {
			mptr = rmptr;
		} else {
			rmptr++;
			i++;
		}
	}

	return mptr;
}

/*--> SANDecodeAux: locate a move from SAN */
nonstatic
mptrT SANDecodeAux(sanT san)
{
	mptrT mptr;

//printf("SAN=%s", san); // DFHhelp

	if(optnv[optn_nmde]) {
		mptr = SANDecode(san);
	} else {
		mptr = SANDecodeFlex(san);
	}

	return mptr;
}

/*<<< sanmnd.c: EOF */
