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.
Tactic generator
Moderators: hgm, Rebel, chrisw
-
- Posts: 620
- Joined: Fri Feb 08, 2008 10:44 am
- Location: Madrid - Spain
-
- Posts: 2663
- Joined: Wed Mar 10, 2010 10:18 pm
- Location: Hamburg, Germany
- Full name: Srdja Matovic
Re: Tactic generator
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
Source Code from Debian:
http://ftp.de.debian.org/debian/pool/ma ... rig.tar.gz
--
Srdja
-
- Posts: 90
- Joined: Sun Nov 02, 2008 4:43 pm
- Location: Barcelona
Re: Tactic generator
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.
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(delta < 30) return false;
if(abs(v2) > abs(v1))
{
if(delta >= abs(v1))
return true;
}
else
{
if(delta >= abs(v1/2))
return true;
}
return false;
}
void Gradient(Board &board,char *fen,int Value,int Gradients[MaxParameters]);
const int ValorTotal = 10;
const bool AnGetEval = true;
void EstudiaPartida(char *Fen,char *mov,int res)
{
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(Fen[0] == '\0')
board.LoadFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -");
else
board.LoadFen(Fen);
// clean up
memset(AnJugadas,0,sizeof(AnJugadas));
memset(AnEval,0,sizeof(AnEval));
memset(AnHValue,0,sizeof(AnHValue));
memset(AnFlags,0,sizeof(AnFlags));
memset(AnFen,0,sizeof(AnFen));
memset(AnFlags,0,sizeof(AnFlags));
AnUltimaJugada = 0;
// trocear las jugadas // Parse Moves
char *stAux = mov;
ptr = mov;
for (; ptr != NULL;)
{
while(*stAux)
{
switch(*stAux)
{
case '*':
case ' ':
*stAux++ = '\0';
while(*stAux == ' ' || *stAux == '.' || *stAux == '\n' || *stAux == '\r' )
*stAux++ = '\0';
goto siguiente;
break;
case '.':
*stAux++ = '\0';
while(*stAux == ' ' || *stAux == '.' || *stAux == '\n' || *stAux == '\r' )
*stAux++ = '\0';
goto siguiente;
break;
case '\n':
*stAux++ = '\0';
while(*stAux == ' ' || *stAux == '.' || *stAux == '\n' || *stAux == '\r' )
*stAux++ = '\0';
goto siguiente;
break;
case '\r':
*stAux++ = '\0';
while(*stAux == ' ' || *stAux == '.' || *stAux == '\n' || *stAux == '\r' )
*stAux++ = '\0';
goto siguiente;
break;
case '{':
while(*stAux != '}' )
stAux++;
stAux++;
*stAux = '\0';
goto siguiente;
break;
}
stAux++;
}
siguiente:
if(!*ptr)
break;
if(strcmp(ptr,"0-1")==0)
{
AnResult = -1;
break;
}
if(strcmp(ptr,"1-0")==0)
{
AnResult = 1;
break;
}
if(strcmp(ptr,"1/2-1/2")==0)
{
AnResult = 0;
break;
}
if(*ptr == '{')
{
// buscamos el numero de jugadas y el valor
int Jug;
double value = GetValue(ptr,&Jug);
if(ACJ) value = -value;
AnEval[AUJ][ACJ][10] = (int)(value * 100);
AnEval[AUJ][ACJ][11] = Jug;
stAux++;
ptr = stAux;
continue;
}
if(strstr(ptr,"/"))
break;
if((*ptr >= '1') && (*ptr <= '9'))
{
if(board.wtm == Black)
{
PrintLog("Error de color en jugada %s\n",ptr);
break;
}
}
else
{
// efectuarlas // Just do it
AnColorJuegan = board.wtm == White ? 0 : 1;
strcpy(AnJugadas[AnUltimaJugada][AnColorJuegan],ptr);
// realizamos el movimiento // do the move
int Move = board.IdentificaPgn(ptr);
if(Move == 0) // unknown abort
{
// illegal move TODO control report...
printf("unknown %s in\n",ptr);
board.Display();
return;
}
UndoData u;
board.DoMove(Move,u);
// board.DoMoveAlgebraic(ptr);
// guardamos el fen de la posicion actual // Save Fen of actual position
board.SaveFEN(AnFen[AnUltimaJugada][AnColorJuegan]);
if(AnGetEval)
{
// Evalua devuelve en funcion del color que le toca jugar
AnEval[AnUltimaJugada][AnColorJuegan][ValorTotal] = board.GetEval();
if(AnColorJuegan == 0) // Normalizamos a valor con blancas
AnEval[AnUltimaJugada][AnColorJuegan][ValorTotal] *= -1;
// Get scores values
AnEval[AnUltimaJugada][AnColorJuegan][0] = 0; //Partida.T.Material;
if(board.isEndGame )
{
AnEval[AnUltimaJugada][AnColorJuegan][0] = board.Material[1];
AnEval[AnUltimaJugada][AnColorJuegan][1] = board.PawnEval[1];
AnEval[AnUltimaJugada][AnColorJuegan][2] = board.DevelopmentEval[1];
AnEval[AnUltimaJugada][AnColorJuegan][3] = board.KnightValue[1];
AnEval[AnUltimaJugada][AnColorJuegan][4] = board.EvalBishop[1];
AnEval[AnUltimaJugada][AnColorJuegan][5] = board.EvalRook[1];
AnEval[AnUltimaJugada][AnColorJuegan][6] = board.EvalQueen[1];
AnEval[AnUltimaJugada][AnColorJuegan][7] = board.PawnCover[1];
AnEval[AnUltimaJugada][AnColorJuegan][8] = board.PiecePlacement[1];
// AnEval[AnUltimaJugada][AnColorJuegan][9] = board.EndGame;
}
else
{
AnEval[AnUltimaJugada][AnColorJuegan][0] = board.Material[0];
AnEval[AnUltimaJugada][AnColorJuegan][1] = board.PawnEval[0];
AnEval[AnUltimaJugada][AnColorJuegan][2] = board.DevelopmentEval[0];
AnEval[AnUltimaJugada][AnColorJuegan][3] = board.KnightValue[0];
AnEval[AnUltimaJugada][AnColorJuegan][4] = board.EvalBishop[0];
AnEval[AnUltimaJugada][AnColorJuegan][5] = board.EvalRook[0];
AnEval[AnUltimaJugada][AnColorJuegan][6] = board.EvalQueen[0];
AnEval[AnUltimaJugada][AnColorJuegan][7] = board.PawnCover[0];
AnEval[AnUltimaJugada][AnColorJuegan][8] = board.PiecePlacement[0];
// AnEval[AnUltimaJugada][AnColorJuegan][9] = board.Opening;
}
}
/* calculate the partial derivative of the eval function with
respect to each of the coefficients. computed
numerically */
Gradient(board,AnFen[AnUltimaJugada][AnColorJuegan],AnEval[AnUltimaJugada][AnColorJuegan][ValorTotal],&Grad[AnUltimaJugada*2+AnColorJuegan][0]);
MatConfigs[AnUltimaJugada*2+AnColorJuegan] = board.MatConfig;
signoConfigs[AnUltimaJugada*2+AnColorJuegan] = board.signoConfig;
AUJ = AnUltimaJugada;
ACJ = AnColorJuegan;
// Get Human like score
AnHValue[AnUltimaJugada][AnColorJuegan] = HumanValue(AnEval[AnUltimaJugada][AnColorJuegan][ValorTotal]);
// marcamos las jugadas forzadas y forzantes jaque/evasiones y capturas
// Flag moves that are forcing/forced (checks/evasion and captures).
// Pendiente Coronaciones // To do queening....
AnFlags[AnUltimaJugada][AnColorJuegan] = AN_NORMAL;
// primero captura
// despues jaques para preservar las evasiones en jaques con captura
if(strstr(AnJugadas[AnUltimaJugada][AnColorJuegan],"="))
AnFlags[AnUltimaJugada][AnColorJuegan] = AN_PROMOTE;
if(strstr(AnJugadas[AnUltimaJugada][AnColorJuegan],"x"))
AnFlags[AnUltimaJugada][AnColorJuegan] = AN_CAPTURE;
if(strstr(AnJugadas[AnUltimaJugada][AnColorJuegan],"+"))
AnFlags[AnUltimaJugada][AnColorJuegan] = AN_CHECK;
if(LastFlag == AN_CHECK)
AnFlags[AnUltimaJugada][AnColorJuegan] = AN_EVASION;
LastFlag = AnFlags[AnUltimaJugada][AnColorJuegan];
LastMat = AnEval[AnUltimaJugada][AnColorJuegan][0];
if(LastFlag == AN_NORMAL)
{
bool DoTacticalAnalisis = false;
// si ha cambiado la evaluacion
// if the eval raise or ....
if(LastNEvalPos != AnHValue[AnUltimaJugada][AnColorJuegan])
{
// si la previa es normal
// dos normales seguidas.
if(AnColorJuegan == 0)
{
if(AnFlags[AnUltimaJugada-1][1] == AN_NORMAL)
{
// miramos si la transicion se considera un error
int v2 = AnEval[AnUltimaJugada][0][ValorTotal];
int v1 = AnEval[AnUltimaJugada-1][1][ValorTotal];
if(IsBlunder(v1,v2))
{
if(v1 > v2)
{
AnFlags[AnUltimaJugada][0] = AN_CRITICAL;
}
else
{
AnFlags[AnUltimaJugada-1][1] = AN_CRITICAL;
}
}
}
else
{
// procesado normal
DoTacticalAnalisis = true;
}
}
else
{
if(AnFlags[AnUltimaJugada][0] == AN_NORMAL)
{
// miramos si la transicion se considera un error
int v2 = AnEval[AnUltimaJugada][1][ValorTotal];
int v1 = AnEval[AnUltimaJugada][0][ValorTotal];
if(IsBlunder(v1,v2))
{
if(v1 > v2)
{
AnFlags[AnUltimaJugada][0] = AN_CRITICAL;
}
else
{
AnFlags[AnUltimaJugada][1] = AN_CRITICAL;
}
}
}
else
{
// procesado normal
DoTacticalAnalisis = true;
}
}
if(DoTacticalAnalisis)
{
// Flag the critical move: the last normal move on the same color to move
// situar la jugada critica
int ultima = AnUltimaJugada-1;
int cc; // color critical
if(LastNEvalPos > AnHValue[AnUltimaJugada][AnColorJuegan])
cc = 0;
else
cc = 1;
while(ultima >= 0 &&
(AnFlags[ultima][cc]&15) != AN_NORMAL && (AnFlags[ultima][cc]&15) != AN_CRITICAL
)
ultima--;
int DifEval = abs(AnEval[AnUltimaJugada][AnColorJuegan][ValorTotal] - AnEval[ultima][cc][ValorTotal]);
if(ultima > 8 && IsBlunder(AnEval[AnUltimaJugada][AnColorJuegan][ValorTotal],AnEval[ultima][cc][ValorTotal])) // DifEval > MIN_SLIGHT_ADV
{
AnFlags[ultima][cc] = AN_CRITICAL; // + ((AnUltimaJugada-ultima)*2 + cc)* 16;
}
}
}
LastNEval = AnUltimaJugada; // last evaluation on normal situation.
LastNEvalPos = AnHValue[AnUltimaJugada][AnColorJuegan] ; // move number of this eval.
}
// increment move number
if(board.wtm == White)
AnUltimaJugada++;
}
ptr = stAux;
}
}
-
- Posts: 620
- Joined: Fri Feb 08, 2008 10:44 am
- Location: Madrid - Spain
Re: Tactic generator
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.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.