Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: Is there an interface to support blunder check of pgn file?

Author: Uri Blass

Date: 12:16:02 12/12/04

Go up one level in this thread


I post my last code to read pgn file that is based on some Crafty's code.
If there are questions about this code I am going to reply about them.

The code of course use some internal functions of movei like
makemove(m) that making move or CheckNextMove(bookbuf) that check if the string
in bookbuf is a legal move and returns 0 in case of illegal move and the move as
integer in case of legal move.

The last function to read the next game is practically unused now but I decided
not to delete it(It had no bugs when I used it but I am not sure that one of the
last changes).

The idea of the varaible flag in the function to read the next game was to
calculate different information on pgn file based on that variable but I decided
that this is not a good solution.



#include "defs.h"
#include "data.h"
#include "protos.h"



char      pgn_event[32] = {"?"};
char      pgn_site[32] = {"?"};
char      pgn_round[32] = {"?"};
char      pgn_date[32] = {"????.??.??"};
char      pgn_white_elo[32] = {""};
char      pgn_white[64] = {"unknown"};
char      pgn_black_elo[32] = {""};
char      pgn_black[64] = {"Movei " VERSION};
char      pgn_result[32] = {"*"};
int read_next_command(FILE* games,int option)
{
	/*read_next_command return -1 if end of file and 0 if move is read and 1 if
header is read
	it also fill bookbuf with the  information in the file as a string
	Later ReadNextMove with bookbuf can be done in case that it is a move*/
	static int data=0,lines_read=0;
	static char input_buffer[512];
	char temp[512],*eof,analysis_move[64];
	int braces=0,parens=0,brackets=0,analysis=0,last_good_line,converted;
	if (!games)
	{
		lines_read=0;
		data=0;
		return 0;
	}
	if (option==-1) data=0;
	if (option==-2) return(lines_read);
	while (1)
	{
		if   (!data)
		{
			eof=fgets (input_buffer,512,games);
			if (!eof) return(-1);
			if (strchr(input_buffer,'\n')) *strchr(input_buffer,'\n')=0;
			if (strchr(input_buffer,'\r')) *strchr(input_buffer,'\r')=' ';
			lines_read++;
			bookbuf[0]=0;
			converted = sscanf(input_buffer,"%s",bookbuf);
			if (bookbuf[0] == '[') do
			{
				 char *bracket1, *bracket2, value[128];
				 strncpy(bookbuf,input_buffer, sizeof bookbuf);
				 bracket1=strchr(input_buffer,'\"');
				 if (bracket1 == 0) return(1);
				 bracket2=strchr(bracket1+1,'\"');
				 if (bracket2 == 0) return(1);
				 *bracket1=0;
				 *bracket2=0;
				 strncpy(value,bracket1+1, sizeof value);
				 if (strstr(input_buffer,"Event")) strncpy(pgn_event,value, sizeof
pgn_event);
				 else if (strstr(input_buffer,"Site")) strncpy(pgn_site,value, sizeof
pgn_site);
				 else if (strstr(input_buffer,"Round")) strncpy(pgn_round,value, sizeof
pgn_round);
				 else if (strstr(input_buffer,"Date")) strncpy(pgn_date,value, sizeof
pgn_date);
				 else if (strstr(input_buffer,"WhiteElo")) strncpy(pgn_white_elo,value,
sizeof pgn_white_elo);
				 else if (strstr(input_buffer,"White")) strncpy(pgn_white,value, sizeof
pgn_white);
				 else if (strstr(input_buffer,"BlackElo")) strncpy(pgn_black_elo,value,
sizeof pgn_black_elo);
				 else if (strstr(input_buffer,"Black")) strncpy(pgn_black,value, sizeof
pgn_black);
				 else if (strstr(input_buffer,"Result")) strncpy(pgn_result,value, sizeof
pgn_result);
				 else if (strstr(input_buffer,"FEN"))
				 {
					 sprintf(bookbuf,"setboard %s",value);
					 setup(value);
				 }
				 return 1;
			 }
			 while(0);
			 data=1;
		}
		/*
----------------------------------------------------------
|                                                          |
|  if we already have data in the bookbuf, it is just a    |
|  matter of extracting the next move and returning it to  |
|  the caller.  if bookbuf is empty, another line has      |
|  to be read in.                                          |
|                                                          |
----------------------------------------------------------
		*/
		else
		{
			bookbuf[0]=0;
			sscanf(input_buffer,"%256s",bookbuf);
			if (strlen(bookbuf) == 0)
			{
				data=0;
				continue;
			}
			else
			{
				char *skip;
				strcpy(temp,input_buffer);
				skip=strstr(input_buffer,bookbuf);
				if (skip) strncpy(input_buffer,skip+strlen(bookbuf), sizeof input_buffer);
			}

			/*
   ----------------------------------------------------------
  |                                                          |
  |  this skips over nested { or ( characters and finds the  |
  |  'mate', before returning any more moves.  it also stops |
  |  if a PGN header is encountered, probably due to an      |
  |  incorrectly bracketed analysis variation.               |
  |                                                          |
   ----------------------------------------------------------
			*/
			last_good_line=lines_read;
			analysis_move[0]=0;
			if (strchr(bookbuf,'{') || strchr(bookbuf,'('))
				while (1)
				{
					char *skip, *ch;
					analysis=1;
					while ((ch=strpbrk(bookbuf,"(){}[]")))
					{
						if (*ch == '(')
						{
							*strchr(bookbuf,'(')=' ';
							if (!braces) parens++;
						}
						if (*ch == ')')
						{
							*strchr(bookbuf,')')=' ';
							if (!braces) parens--;
						}
						if (*ch == '{')
						{
							*strchr(bookbuf,'{')=' ';
							braces++;
						}
						if (*ch == '}')
						{
							*strchr(bookbuf,'}')=' ';
							braces--;
						}
						if (*ch == '[')
						{
							*strchr(bookbuf,'[')=' ';
							if (!braces) brackets++;
						}
						if (*ch == ']')
						{
							*strchr(bookbuf,']')=' ';
							if (!braces) brackets--;
						}
					}
					if (analysis && analysis_move[0]==0)
					{
						if (strspn(bookbuf," ") != strlen(bookbuf))
						{
							char *tmove=analysis_move;
							sscanf(bookbuf,"%64s",analysis_move);
							strcpy(bookbuf,analysis_move);
							if (strcmp(bookbuf,"0-0") && strcmp(bookbuf,"0-0-0"))
								tmove=bookbuf+strspn(bookbuf,"0123456789.");
							else
								tmove=bookbuf;
							if ((tmove[0]>='a' && tmove[0]<='z') ||(tmove[0]>='A' && tmove[0]<='Z')
||
								!strcmp(tmove,"0-0") || !strcmp(tmove,"0-0-0"))
								strcpy(analysis_move,bookbuf);
							else
								analysis_move[0]=0;
						}
					}
					if (parens==0 && braces==0 && brackets==0) break;
					bookbuf[0]=0;
					sscanf(input_buffer,"%s",bookbuf);
					if (strlen(bookbuf) == 0)
					{
						eof=fgets(input_buffer,512,games);
						if (!eof)
						{
							parens=0;
							braces=0;
							brackets=0;
							return(-1);
						}
						if (strchr(input_buffer,'\n')) *strchr(input_buffer,'\n')=0;
						if (strchr(input_buffer,'\r')) *strchr(input_buffer,'\r')=' ';
						lines_read++;
						if (lines_read-last_good_line >= 100)
						{
							parens=0;
							braces=0;
							brackets=0;
							Print("ERROR.  comment spans over 100 lines, starting at line
%d\n",last_good_line);
							break;
						}
					}
					strcpy(temp,input_buffer);
					skip=strstr(input_buffer,bookbuf)+strlen(bookbuf);
					strcpy(input_buffer,skip);
				}
				else
				{
					int skip;
					if ((skip=strspn(bookbuf,"0123456789.")))
					{
						char temp[512];
						strcpy(temp,bookbuf+skip);
						strcpy(bookbuf,temp);
					}
					if (isalpha(bookbuf[0]) || strchr(bookbuf,'-'))
						return(0);
				}
         }
   }
}
int result;
int games_parsed;

FILE *games;

int openpgn(char * gamesname)
{
	games=fopen(gamesname ,"r+b");
	if (games)
	{
		fseek(games,0,SEEK_SET);
		return 1;
	}
	return 0;
}
void parseheader()
{
if (strstr(bookbuf,"Site"))
				{

					result=3;
				}
				else if (strstr(bookbuf,"esult"))
				{
					games_parsed++;
					if (strstr(bookbuf,"1-0")) result=2;
					else if (strstr(bookbuf,"0-1")) result=1;
					else if (strstr(bookbuf,"1/2-1/2")) result=0;
					else if (strstr(bookbuf,"*")) result=3;
				}
}
int pgn_ok;
int handle_possible_error(void)
{
	int data_read=0;
	if
(strspn(bookbuf,"0123456789/-.*")!=strlen(bookbuf)&&(hply<max_plies_of_game))
	{
		pgn_ok=0;
		printf("%s-",pgn_white);
		printf(" %s ",pgn_black);
		printf("ply err%d ",hply);
		printf(" move %s is illegal line %d ",bookbuf,read_next_command(games,-2));
		printf("\n");
		read_next_command(games,-1);
	}
	setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
	while (data_read==0)
		data_read=read_next_command(games,0);
	if (data_read==-1)
		fclose(games);
	return data_read;
}
int get_next_move_in_pgn(void)
{
	/*this function read next command from file games that is already opened
	until it see a new move that mean new interesting position
	because move was done from it.
	it returns the move in case of finding a move print error and change global
flag
	from 0 to 1 when it finds error and care to close the file when there are no
more moves
	or 0 in case that it does not find a new move
	it calculates relevant information like the result of the game during the
process
	*/
	int move;
	int data_read;
	char *ch;
	do
	{
		/*we go out of the loop after reading a legal move or at the end of the file*/
		data_read=read_next_command(games,0);
		if (data_read==1)
			parseheader();
		if (data_read==-1)
			return 0;
		if (data_read==0)
		{
			/*clean the move and check maybe you need to skip the move*/
			if ((ch = strpbrk(bookbuf, "?!")))
					*ch = 0;
			/*you may need to skip this command and read next command in case that it is
			a comment instead of a move*/
			if (!strchr(bookbuf,'$')&&!strchr(bookbuf,'*'))
			{
				if (hply<max_plies_of_game)
					move=CheckNextMove(bookbuf);
				else
					move=0;
				/*if move>0 the program is going to return move because the loop is finished
by data_read==0
				and move>0*/
				if (move<=0)
				{
					/*if we are here there are 3 possibilities
					1)we finished a game
					2)we have an error
					3)number of plies in games is too high

					handle possible error read moves until getting no move
					handle possible error also print in the screen error message in case of
getting no move
					inspite of expecting move based on the string*/

					data_read=handle_possible_error();
						if (data_read==-1)
							return 0;

				/*data_read is going to be not 0 and it means that the program will continue
to read until
				it gets real move after header*/
				}
			}

		}
	}
	while ((data_read==1)||(move<=0));
	return move;

}



void only_check(char*gamename)
{
	pgn_ok=1;
	int m;
	/*this procedure only print mistakes in pgn by the function get_next_move()
	get_next_move() not only find the next move in pgn file but
	also change the value of the global variable of pgn_ok from 1 to 0
	when it finds mistakes*/
	setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
	m=get_next_move_in_pgn();
	while (m>0)
	{
		makemove(m);
		m=get_next_move_in_pgn();
	}
}
void translateepd(char* gamename)
{
	int m=get_next_move_in_pgn();
	char *candidatefen;
	pgntoepd = fopen("pgntoepd.epd","w+");
	if (pgntoepd==NULL)
	{
		fclose(games);
		return;
	}
	while (m>0)
	{
		candidatefen=translate_pos_to_fen();
		fprintf(pgntoepd,"%s\n",candidatefen);
		makemove(m);
		m=get_next_move_in_pgn();
	}

}

int startpgn(char *gamesname)
{
	int data_read;
	games_parsed=0;
	setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
	read_next_command(0,0);
	/*first read_next_command only does some initialization stuff because 0 is not
pointer to file*/
	if  (openpgn(gamesname))
	{
		do
			data_read=read_next_command(games,0);
		while (data_read==0);
		if (data_read==-1)
		{
			/*there is no header in the pgn before end of file so we have not place to
start to read moves
			I guess that the user did a mistake by giving the computer a wrong file that
exists*/
			fclose(games);
			return 0;
		}
		parseheader();
		return 1;
	}
	/*there is no pgn*/
	return 0;
}
void calc_sum_perft(char *gamesname,int i)
{
	int m;
	BitBoard sumperftpgn=0;
	if (i<1)
		return;
	setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
	m=get_next_move_in_pgn();
	while (m>0)
	{
		sumperftpgn+=perft(i-1);
		makemove(m);
		m=get_next_move_in_pgn();
	}
	printf("perft=%I64u \n",sumperftpgn);
}
void perftpgn(char *gamesname,int depth)
{
	if (startpgn(gamesname))
		calc_sum_perft(gamesname,depth);
}
void calc_draw(char *gamesname)
{
	int m;
	setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
	m=get_next_move_in_pgn();
	while (m>0)
	{
		if (detectdraw())
			if (result>1)
			{
		//		printf("%d",bishops[0][0]);
				printf(" %s ",pgn_white);
				printf(" %s ",pgn_black);
				printf(" %s ",translate_pos_to_fen());
			printf("%d\n",result);
			}
		makemove(m);
		m=get_next_move_in_pgn();
	}
}
void drawpgn(char *gamesname)
{
	if (startpgn(gamesname))
		calc_draw(gamesname);
}

int checkpgn(char *gamesname)
{
	if (startpgn(gamesname))
		only_check(gamesname);
	printf("games= %d\n",games_parsed);
	return pgn_ok;
}

void translatepgn_to_epd(char * gamesname)
{
	if (startpgn(gamesname))
		translateepd(gamesname);
}




/*unused function*/

int readnextgame(int flag)
{
	int data_read=0;
	int move;
	char *ch;
	char *candidatefen;

	while (data_read==0)
	{


		/*need to add reading ? and !  but it is not important now*/

		if ((ch = strpbrk(bookbuf, "?!")))
              *ch = 0;

		if (!strchr(bookbuf,'$')&&!strchr(bookbuf,'*'))
		{

			if (hply<max_plies_of_game)
				move=CheckNextMove(bookbuf);
			else
				move=0;
			if (move>0)
			{

				if (flag==-2)
				{
					candidatefen=translate_pos_to_fen();
					fprintf(pgntoepd,"%s\n",candidatefen);
				}
				makemove(move);
			}
			else
			{
				data_read=handle_possible_error();
				if (data_read!=0)
					break;
			}
		}
		data_read=read_next_command(games,0);
	}
	setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
	return data_read;
}



This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.