/*>>> epdglue.c: glue to connect KnightCap to the EPD Kit routines */

/* Revised: 1998.04.18 */

/*
Copyright (C) 1996 by Steven J. Edwards (sje@mv.mv.com)
All rights reserved.  This code may be freely redistibuted and used by
both research and commerical applications.  No warranty exists.
*/

/*
The contents of this source file form the programmatic glue between
the host program KnightCap and the EPD Kit.  Therefore, this file will
have to be changed if used with a different host program.  Also, the
contents of the prototype include file (epdglue.h) may also require
modification for a different host.

The contents of the other source files in the EPD Kit (epddefs.h,
epd.h, and epd.c) should not have to be changed for different hosts.
*/

/*
This file was originally prepared on an Apple Macintosh using the
Metrowerks CodeWarrior 6 ANSI C compiler.  Tabs are set at every
four columns.  Further testing and development was performed on a
generic PC running Linux 1.2.9 and using the gcc 2.6.3 compiler.
*/

/* KnightCap includes */
#include "includes.h"
#include "knightcap.h"

/* EPD Kit definitions (host program independent) */
#include "epddefs.h"

/* EPD Kit routine prototypes (host program independent) */
#include "epd.h"

/* prototypes for this file (host program dependent) */
#include "epdglue.h"

/* KnightCap's board is the transpose of EPD */
#define transpose(sq) ((map_file((sq)) << 3) | map_rank((sq)));

static gamptrT default_gamptr;

/*--> EGMapFromHostColor: map a color from the host to the EPD style */
static
cT
EGMapFromHostColor(siT color)
{
cT c;

/* this is an internal glue routine */

/* map from KnightCap's color representation */

if (color == 1)
	c = c_w;
else
	c = c_b;

return (c);
}

/*--> EGMapToHostColor: map a color to the host from the EPD style */
static
siT
EGMapToHostColor(cT c)
{
siT color;

/* this is an internal glue routine */

/* map to KnightCap's color representation */

if (c == c_w)
	color = 1;
else
	color = -1;

return (color);
}

/*--> EGMapFromHostPiece: map a piece from the host to the EPD style */
static
pT
EGMapFromHostPiece(siT piece)
{
pT p;

/* this is an internal glue routine */

/* map from KnightCap's piece representation */

switch (piece)
	{
	case PAWN:
		p = p_p;
		break;
	case KNIGHT:
		p = p_n;
		break;
	case BISHOP:
		p = p_b;
		break;
	case ROOK:
		p = p_r;
		break;
	case QUEEN:
		p = p_q;
		break;
	case KING:
		p = p_k;
		break;
	default:
		p = p_nil;
		break;
	};

return (p);
}

/*--> EGMapToHostPiece: map a piece to the host from the EPD style */
static
siT
EGMapToHostPiece(pT p)
{
siT piece=0;

/* this is an internal glue routine */

/* map to KnightCap's piece representation */

switch (p)
	{
	case p_p:
		piece = PAWN;
		break;
	case p_n:
		piece = KNIGHT;
		break;
	case p_b:
		piece = BISHOP;
		break;
	case p_r:
		piece = ROOK;
		break;
	case p_q:
		piece = QUEEN;
		break;
	case p_k:
		piece = KING;
		break;
	};

return (piece);
}

/*--> EGMapFromHostCP: map a color piece from the host to the EPD style */
static
cpT
EGMapFromHostCP(siT hostcp)
{
cpT cp=0;

/* this is an internal glue routine */

/* map from KnightCap's color-piece representation */

switch (hostcp)
	{
	case -QUEEN:
		cp = cp_bq;
		break;
	case -ROOK:
		cp = cp_br;
		break;
	case -BISHOP:
		cp = cp_bb;
		break;
	case -KING:
		cp = cp_bk;
		break;
	case -KNIGHT:
		cp = cp_bn;
		break;
	case -PAWN:
		cp = cp_bp;
		break;
	case NONE:
		cp = cp_v0;
		break;
	case PAWN:
		cp = cp_wp;
		break;
	case KNIGHT:
		cp = cp_wn;
		break;
	case KING:
		cp = cp_wk;
		break;
	case BISHOP:
		cp = cp_wb;
		break;
	case ROOK:
		cp = cp_wr;
		break;
	case QUEEN:
		cp = cp_wq;
		break;
	};

return (cp);
}

/*--> EGMapToHostCP: map a color piece to the host from the EPD style */
static
siT
EGMapToHostCP(cpT cp)
{
siT hostcp=0;

/* this is an internal glue routine */

/* map to KnightCap's color-piece representation */

switch (cp)
	{
	case cp_wp:
		hostcp = PAWN;
		break;
	case cp_wn:
		hostcp = KNIGHT;
		break;
	case cp_wb:
		hostcp = BISHOP;
		break;
	case cp_wr:
		hostcp = ROOK;
		break;
	case cp_wq:
		hostcp = QUEEN;
		break;
	case cp_wk:
		hostcp = KING;
		break;
	case cp_bp:
		hostcp = -PAWN;
		break;
	case cp_bn:
		hostcp = -KNIGHT;
		break;
	case cp_bb:
		hostcp = -BISHOP;
		break;
	case cp_br:
		hostcp = -ROOK;
		break;
	case cp_bq:
		hostcp = -QUEEN;
		break;
	case cp_bk:
		hostcp = -KING;
		break;
	case cp_v0:
		hostcp = NONE;
		break;
	};

return (hostcp);
}

/*--> EGMapFromHostSq: map square index from host style */
static
sqT
EGMapFromHostSq(siT index)
{
sqT sq;

/* this is an internal glue routine */

/* KnightCap's square index is the transpose of the EPD Kit square index */

sq = transpose(index);

return (sq);
}

/*--> EGMapToHostSq: map square index to host style */
static
siT
EGMapToHostSq(sqT sq)
{
siT index;

/* this is an internal glue routine */

/* KnightCap's square index is the transpose of the EPD Kit square index */

index = transpose(sq); 

return (index);
}

/*--> EGMapFromHostScore: map score from host style */
static
cpevT
EGMapFromHostScore(liT score)
{
cpevT cpev;
liT distance;

/* this is an internal EPD glue routine */

/* check for a forced mate */

if (score >= FORCED_WIN)
	{
	/* convert forced mate score */

	distance = (WIN - score) / 2;
	cpev = synth_mate(distance);
	}
else
	if (score <= -FORCED_WIN)
		{
		/* convert forced loss score */

		distance = (WIN + score) / 2;
		cpev = synth_loss(distance);
		}
	else
		{
		/* convert regular score */

		cpev = score*100/STATIC_PAWN_VALUE;
		};

return (cpev);
}

/*--> EGMapToHostScore: map score to host style */
static
etype
EGMapToHostScore(cpevT cpev)
{
liT score;

/* this is an internal EPD glue routine */

/* check for a forced mate */

if (forced_mate(cpev))
	{
	/* convert forced mate score */

	score = WIN - (etype)(cpev_best-cpev+1);
	}
else
	if (forced_loss(cpev))
		{
		/* convert forced loss score */

		score = -WIN + (etype)(cpev_best+cpev+1);
		}
	else
		{
		/* convert regular score */

		score = ((etype) cpev) * STATIC_PAWN_VALUE/100;
		};

return (score);
}


/*--> EGGetIndexedHostPosition: copy from indexed host position */
static
void
EGGetIndexedHostPosition(Position *b)
{
sqT sq;
rbT rb;
cT actc;
castT cast;
sqT epsq;
siT hmvc;
siT fmvn;

/* this is an internal EPD glue routine */

/*
This routine is called from within the EPD glue to copy the host program's
current position at the given dpeth into the EPD Kit.  Information about
the previous EPD Kit current position is lost.
*/

/* read from the host piece placement */

for (sq = sq_a1; sq <= sq_h8; sq++)
	rb.rbv[sq] =
		EGMapFromHostCP(b->board[EGMapToHostSq(sq)]);

/* read from the host piece active color */

actc = EGMapFromHostColor(next_to_play(b));

/* read from the host piece castling availability */

cast = 0;

if (b->flags & WHITE_CASTLE_LONG)
	cast |= cf_wq;
if (b->flags & WHITE_CASTLE_SHORT)
	cast |= cf_wk;
if (b->flags & BLACK_CASTLE_LONG)
	cast |= cf_bq;
if (b->flags & BLACK_CASTLE_SHORT)
	cast |= cf_bk;

/* read from the host piece en passant target square */

if (b->enpassent == 0)
	epsq = sq_nil;
else 
	epsq = transpose(sq);

/* read from the host halfmove clock */

hmvc = b->fifty_count;

/* read from the host fullmove number */

fmvn = b->move_num;

/* set the EPD current position */

EPDSetCurrentPosition(&rb, actc, cast, epsq, hmvc, fmvn);

return;
}


/*--> EGTBScore: fetch a tablebase score for the indicated position */
nonstatic
int
EGTBScore(Position *b, etype *scoreptr)
{
siT flag;
cpevT cpev;

/* this routine is called from KnightCap at various points in the search */

/* set default return value: score unfound */

flag = 0;
*scoreptr = 0;

/* copy the indexed host position as the EPD Kit new current position */

EGGetIndexedHostPosition(b);

/* perform the probe */

cpev = EPDTBScore();
if (cpev != cpev_wrck)
	{
	/* set return value */

	flag = 1;

	/* convert and copy score */

	*scoreptr = EGMapToHostScore(cpev);
	};

return (flag);
}

/*--> EGInit: one time EPD glue initialization */
nonstatic
void
EGInit(void)
{
tbidT tbid;
cT c;
siT count;
static int initialised;

if (initialised)
	return;

lprintf(0, "EPD Kit revision date: 1996.04.21\n");

/* call the EPD one time set up code */

EPDInit();

/* set up the default game structure */

default_gamptr = EPDGameOpen();

/* tablebase survey */

count = 0;
for (tbid = 0; tbid < tbidL; tbid++)
	for (c = c_w; c <= c_b; c++)
		if (EPDTBIsFilePresent(tbid, c))
			count++;

if (count == 0)
	{
	lprintf(0,"No tablebase files found in the %s directory.\n",tb_path);
	}
else
	{
	lprintf(0,"%hd tablebase file(s) found in the %s directory.\n",
		count, tb_path);
	};

initialised = 1;
return;
}

/*--> EGTerm: one time EPD glue termination */
nonstatic
void
EGTerm(void)
{
/* this is called by Option() in option.c */

/* release the default game structure */

if (default_gamptr != NULL)
	EPDGameClose(default_gamptr);

/* call the EPD one time close down code */

EPDTerm();

return;
}

/*<<< epdglue.c: EOF */
