Tactic generator

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
Kempelen
Posts: 620
Joined: Fri Feb 08, 2008 10:44 am
Location: Madrid - Spain

Tactic generator

Post by Kempelen »

Hello
Does any of you know of any tool (or source code) that will take a pgn file and generate an output file of tactic-type positions like 'side to move an win'? (I suppose an external engine would be necesary, or at less certain logic into the tool to can recognize winning searches). Source code would be nice apreciated.
thanks.
Fermin Serrano
Author of 'Rodin' engine
http://sites.google.com/site/clonfsp/
smatovic
Posts: 2663
Joined: Wed Mar 10, 2010 10:18 pm
Location: Hamburg, Germany
Full name: Srdja Matovic

Re: Tactic generator

Post by smatovic »

Polyglot by Fabien Letouzey has an Opening Book Creation Component, with an built in PGN Parser, well written and easy to modify.

Source Code from Debian:

http://ftp.de.debian.org/debian/pool/ma ... rig.tar.gz

--
Srdja
Antonio Torrecillas
Posts: 90
Joined: Sun Nov 02, 2008 4:43 pm
Location: Barcelona

Re: Tactic generator

Post by Antonio Torrecillas »

Extracted from my jiminy.cpp (named after Jiminy Cricket).

This is a simple parser for the moves of a game.
It gives you a tabular data for static evaluation and it try to flag moves that are likely to be blunders.(Critical)
I hope you find this usefull and have success to clean it up and adapt it to your needs.


Code: Select all

// estudio de un pgn para generar un epd con las jugadas críticas.

// Dif. Human perception
#define MIN_DECISIVE_ADV 150
#define MIN_MODERATE_ADV  70
#define MIN_SLIGHT_ADV    30

// coding Human Values
#define HV_EQUAL 0
#define HV_BL_SLIGHT_ADV -1
#define HV_BL_MODERATE_ADV -2
#define HV_BL_DECISIVE_ADV -3
#define HV_WH_SLIGHT_ADV 1
#define HV_WH_MODERATE_ADV 2
#define HV_WH_DECISIVE_ADV 3

// Coding move's type 
#define AN_NORMAL 0
#define AN_CHECK 1
#define AN_CAPTURE 2
#define AN_EVASION 3
#define AN_PROMOTE 5
#define AN_CRITICAL 6


// analisis de partidas
int AnEval[400][2][12]; // jugada, color, 12 apartados de evaluación
int AUJ,ACJ;

double tanhv[800];  // squash evaluation
double dt[800];
int Grad[800][MaxParameters];
int MatConfigs[800];
int signoConfigs[800];
int AnHValue[400][2];	// valoración humana
int AnFlags[400][2];	// marca de jugadas particulares forzadas jaques capturas etc...
char AnFen[400][2][120];	// FEN de cada posición analizada
char AnJugadas[400][2][7];	// colección de movimientos
char AnEvent[250];	// evento wccc2006 por ejemplo
char AnRound[20];
char AnWhite[250];
char AnBlack[250];
int AnResult;
//int AnVQuiesce[400][2];
//char *AnPQuiesce[400][2];

int AnColorJuegan;
int AnUltimaJugada;





extern int HumanValue(int x);

bool IsBlunder(int v1,int v2)
{
	int delta = abs(v1-v2);
	if&#40;delta < 30&#41; return false;
	if&#40;abs&#40;v2&#41; > abs&#40;v1&#41;)
	&#123;
		if&#40;delta >= abs&#40;v1&#41;) 
			return true;
	&#125;
	else
	&#123;
		if&#40;delta >= abs&#40;v1/2&#41;) 
			return true;
	&#125;
	return false;
&#125;


void 	Gradient&#40;Board &board,char *fen,int Value,int Gradients&#91;MaxParameters&#93;);

const int ValorTotal = 10;
const bool AnGetEval = true;

void EstudiaPartida&#40;char *Fen,char *mov,int res&#41;
&#123;
	char *ptr;
	int LastFlag = AN_NORMAL; // last flag move
	int LastMat = 0;	// last material eval.
	int LastNEval = 0; // last evaluation on normal situation.
	int LastNEvalPos = 0; // move number of this eval.
	AnResult = 0;
	Board board;
	if&#40;Fen&#91;0&#93; == '\0')
		board.LoadFen&#40;"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -");
	else
		board.LoadFen&#40;Fen&#41;;
	// clean up
	memset&#40;AnJugadas,0,sizeof&#40;AnJugadas&#41;);
	memset&#40;AnEval,0,sizeof&#40;AnEval&#41;);
	memset&#40;AnHValue,0,sizeof&#40;AnHValue&#41;);
	memset&#40;AnFlags,0,sizeof&#40;AnFlags&#41;);
	memset&#40;AnFen,0,sizeof&#40;AnFen&#41;);
	memset&#40;AnFlags,0,sizeof&#40;AnFlags&#41;);
	AnUltimaJugada = 0;
	// trocear las jugadas // Parse Moves
	char *stAux = mov;
	ptr = mov;
   for (; ptr != NULL;) 
   &#123;
	   while&#40;*stAux&#41;
	   &#123;
		   switch&#40;*stAux&#41;
		   &#123;
		   case '*'&#58;
		   case ' '&#58;
			   *stAux++ = '\0';
			   while&#40;*stAux == ' ' || *stAux == '.' || *stAux == '\n' || *stAux == '\r' )
				   *stAux++ = '\0';
			   goto siguiente;
			   break;
		   case '.'&#58;
			   *stAux++ = '\0';
			   while&#40;*stAux == ' ' || *stAux == '.' || *stAux == '\n' || *stAux == '\r' )
				   *stAux++ = '\0';
			   goto siguiente;
			   break;
		   case '\n'&#58;
			   *stAux++ = '\0';
			   while&#40;*stAux == ' ' || *stAux == '.' || *stAux == '\n' || *stAux == '\r' )
				   *stAux++ = '\0';
			   goto siguiente;
			   break;
		   case '\r'&#58;
			   *stAux++ = '\0';
			   while&#40;*stAux == ' ' || *stAux == '.' || *stAux == '\n' || *stAux == '\r' )
				   *stAux++ = '\0';
			   goto siguiente;
			   break;
		   case '&#123;'&#58;
			   while&#40;*stAux != '&#125;' )
				   stAux++;
			   stAux++;
			   *stAux = '\0';
			   goto siguiente;
			   break;
		   &#125;
		   stAux++;
	   &#125;
siguiente&#58;
	   if&#40;!*ptr&#41;
		   break;
	   if&#40;strcmp&#40;ptr,"0-1")==0&#41;
	   &#123;
		   AnResult = -1;
		   break;
	   &#125;
	   if&#40;strcmp&#40;ptr,"1-0")==0&#41;
	   &#123;
		   AnResult = 1;
		   break;
	   &#125;
	   if&#40;strcmp&#40;ptr,"1/2-1/2")==0&#41;
	   &#123;
		   AnResult = 0;
		   break;
	   &#125;
	   if&#40;*ptr == '&#123;')
	   &#123;
		   // buscamos el numero de jugadas y el valor
		   int Jug;
		   double value = GetValue&#40;ptr,&Jug&#41;;
		   if&#40;ACJ&#41; value = -value;
   			AnEval&#91;AUJ&#93;&#91;ACJ&#93;&#91;10&#93; = &#40;int&#41;&#40;value * 100&#41;;
   			AnEval&#91;AUJ&#93;&#91;ACJ&#93;&#91;11&#93; = Jug;
			stAux++;
			ptr = stAux;
			continue;
	   &#125;
	   if&#40;strstr&#40;ptr,"/"))
		   break;
	   if&#40;(*ptr >= '1') && (*ptr <= '9'))
	   &#123;
		   if&#40;board.wtm == Black&#41;
		   &#123;
			   PrintLog&#40;"Error de color en jugada %s\n",ptr&#41;;
			   break;
		   &#125;
	   &#125;
	   else
	   &#123;
		// efectuarlas // Just do it
		   AnColorJuegan = board.wtm == White ? 0 &#58; 1;
		   strcpy&#40;AnJugadas&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;,ptr&#41;;
		   // realizamos el movimiento // do the move
		   int Move = board.IdentificaPgn&#40;ptr&#41;;
		   if&#40;Move == 0&#41; // unknown abort
		   &#123;
			   // illegal move TODO control report...
			   printf&#40;"unknown %s in\n",ptr&#41;;
			   board.Display&#40;);
			   return;
		   &#125;
		   UndoData u;
		   board.DoMove&#40;Move,u&#41;;
//		   board.DoMoveAlgebraic&#40;ptr&#41;;
		   // guardamos el fen de la posicion actual // Save Fen of actual position
		   board.SaveFEN&#40;AnFen&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;);
		   if&#40;AnGetEval&#41;
		   &#123;
		   // Evalua devuelve en funcion del color que le toca jugar
		   AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;ValorTotal&#93; = board.GetEval&#40;);
		   if&#40;AnColorJuegan == 0&#41; // Normalizamos a valor con blancas
			AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;ValorTotal&#93; *= -1;
		   // Get scores values
			AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;0&#93; = 0; //Partida.T.Material;
			if&#40;board.isEndGame )
			&#123;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;0&#93; = board.Material&#91;1&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;1&#93; = board.PawnEval&#91;1&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;2&#93; = board.DevelopmentEval&#91;1&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;3&#93; = board.KnightValue&#91;1&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;4&#93; = board.EvalBishop&#91;1&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;5&#93; = board.EvalRook&#91;1&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;6&#93; = board.EvalQueen&#91;1&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;7&#93; = board.PawnCover&#91;1&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;8&#93; = board.PiecePlacement&#91;1&#93;;
//				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;9&#93; = board.EndGame;
			&#125;
			else
			&#123;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;0&#93; = board.Material&#91;0&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;1&#93; = board.PawnEval&#91;0&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;2&#93; = board.DevelopmentEval&#91;0&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;3&#93; = board.KnightValue&#91;0&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;4&#93; = board.EvalBishop&#91;0&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;5&#93; = board.EvalRook&#91;0&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;6&#93; = board.EvalQueen&#91;0&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;7&#93; = board.PawnCover&#91;0&#93;;
				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;8&#93; = board.PiecePlacement&#91;0&#93;;
//				AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;9&#93; = board.Opening;
			&#125;
		   &#125;
			/* calculate the partial derivative of the eval function with
			   respect to each of the coefficients. computed
			   numerically */
			Gradient&#40;board,AnFen&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;,AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;ValorTotal&#93;,&Grad&#91;AnUltimaJugada*2+AnColorJuegan&#93;&#91;0&#93;);
			MatConfigs&#91;AnUltimaJugada*2+AnColorJuegan&#93; = board.MatConfig;
			signoConfigs&#91;AnUltimaJugada*2+AnColorJuegan&#93; = board.signoConfig;

			AUJ = AnUltimaJugada;
			ACJ = AnColorJuegan;
			// Get Human like score
			AnHValue&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93; = HumanValue&#40;AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;ValorTotal&#93;);
	    	// marcamos las jugadas forzadas y forzantes jaque/evasiones y capturas
			// Flag moves that are forcing/forced &#40;checks/evasion and captures&#41;.
			// Pendiente Coronaciones // To do queening....
			AnFlags&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93; = AN_NORMAL;
			// primero captura
			// despues jaques para preservar las evasiones en jaques con captura			
			if&#40;strstr&#40;AnJugadas&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;,"=")) 
				AnFlags&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93; = AN_PROMOTE;
			if&#40;strstr&#40;AnJugadas&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;,"x")) 
				AnFlags&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93; = AN_CAPTURE;
			if&#40;strstr&#40;AnJugadas&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;,"+")) 
				AnFlags&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93; = AN_CHECK;
			if&#40;LastFlag == AN_CHECK&#41;
				AnFlags&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93; = AN_EVASION;

			LastFlag = AnFlags&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;;
			LastMat = AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;0&#93;;
			if&#40;LastFlag == AN_NORMAL&#41;
			&#123;
				bool DoTacticalAnalisis = false;
				// si ha cambiado la evaluacion
				// if the eval raise or ....
				if&#40;LastNEvalPos != AnHValue&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;)
				&#123;
					// si la previa es normal
					// dos normales seguidas.
					if&#40;AnColorJuegan == 0&#41;
					&#123;
						if&#40;AnFlags&#91;AnUltimaJugada-1&#93;&#91;1&#93; == AN_NORMAL&#41;
						&#123;
							// miramos si la transicion se considera un error
							int v2 = AnEval&#91;AnUltimaJugada&#93;&#91;0&#93;&#91;ValorTotal&#93;;
							int v1 = AnEval&#91;AnUltimaJugada-1&#93;&#91;1&#93;&#91;ValorTotal&#93;;
							if&#40;IsBlunder&#40;v1,v2&#41;)
							&#123;
								if&#40;v1 > v2&#41;
								&#123;
									AnFlags&#91;AnUltimaJugada&#93;&#91;0&#93; = AN_CRITICAL;
								&#125;
								else
								&#123;
									AnFlags&#91;AnUltimaJugada-1&#93;&#91;1&#93; = AN_CRITICAL;
								&#125;

							&#125;
						&#125;
						else
						&#123;
							// procesado normal
							DoTacticalAnalisis = true;
						&#125;
					&#125;
					else
					&#123;
						if&#40;AnFlags&#91;AnUltimaJugada&#93;&#91;0&#93; == AN_NORMAL&#41;
						&#123;
							// miramos si la transicion se considera un error
							int v2 = AnEval&#91;AnUltimaJugada&#93;&#91;1&#93;&#91;ValorTotal&#93;;
							int v1 = AnEval&#91;AnUltimaJugada&#93;&#91;0&#93;&#91;ValorTotal&#93;;
							if&#40;IsBlunder&#40;v1,v2&#41;)
							&#123;
								if&#40;v1 > v2&#41;
								&#123;
									AnFlags&#91;AnUltimaJugada&#93;&#91;0&#93; = AN_CRITICAL;
								&#125;
								else
								&#123;
									AnFlags&#91;AnUltimaJugada&#93;&#91;1&#93; = AN_CRITICAL;
								&#125;

							&#125;
						&#125;
						else
						&#123;
							// procesado normal
							DoTacticalAnalisis = true;
						&#125;
					&#125;
					if&#40;DoTacticalAnalisis&#41;
					&#123;
						// Flag the critical move&#58; the last normal move on the same color to move
						// situar la jugada critica
						int ultima = AnUltimaJugada-1;
						int cc; // color critical
						if&#40;LastNEvalPos > AnHValue&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;)
							cc = 0;
						else
							cc = 1;
						while&#40;ultima >= 0 && 
							&#40;AnFlags&#91;ultima&#93;&#91;cc&#93;&15&#41; != AN_NORMAL && &#40;AnFlags&#91;ultima&#93;&#91;cc&#93;&15&#41; != AN_CRITICAL 
							)
							ultima--;
						int DifEval = abs&#40;AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;ValorTotal&#93; - AnEval&#91;ultima&#93;&#91;cc&#93;&#91;ValorTotal&#93;);
						if&#40;ultima > 8 && IsBlunder&#40;AnEval&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93;&#91;ValorTotal&#93;,AnEval&#91;ultima&#93;&#91;cc&#93;&#91;ValorTotal&#93;)) // DifEval > MIN_SLIGHT_ADV
						&#123;
								AnFlags&#91;ultima&#93;&#91;cc&#93; = AN_CRITICAL; // + (&#40;AnUltimaJugada-ultima&#41;*2 + cc&#41;* 16;
						&#125;
					&#125;
				&#125;
				LastNEval = AnUltimaJugada; // last evaluation on normal situation.
				LastNEvalPos = AnHValue&#91;AnUltimaJugada&#93;&#91;AnColorJuegan&#93; ; // move number of this eval.
			&#125;

			// increment move number
		   if&#40;board.wtm == White&#41;
			   AnUltimaJugada++;
	   &#125;
	   ptr = stAux;
   &#125;
&#125;
User avatar
Kempelen
Posts: 620
Joined: Fri Feb 08, 2008 10:44 am
Location: Madrid - Spain

Re: Tactic generator

Post by Kempelen »

Antonio Torrecillas wrote:Extracted from my jiminy.cpp (named after Jiminy Cricket).

This is a simple parser for the moves of a game.
It gives you a tabular data for static evaluation and it try to flag moves that are likely to be blunders.(Critical)
I hope you find this usefull and have success to clean it up and adapt it to your needs.
Thank you very much for your contribution. Your code is quite understandable and easy to read. Unfortunatly it assumes the moves are commented with its corresponding eval. I was thinking something more sophisticated, like a tool which load an engine or a tool which altough not been a good engine, could be enough to detect tactics given it enought time.
Fermin Serrano
Author of 'Rodin' engine
http://sites.google.com/site/clonfsp/