/***************************************************************************
qgtp.cpp  -  description
-------------------
begin                : Thu Nov 29 2001
copyright            : (C) 2001 by PALM Thomas , DINTILHAC Florian, HIVERT Anthony, PIOC Sebastien
email                : 
***************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/


#include <stdio.h>
//#include <unistd.h>
#include <stdlib.h>
//#include <qprocess.h>
enum CommandType {PROTOCOL, BOARDSIZE, KNOWN_COMMAND, LEVEL, KOMI, PLAY_BLACK, PLAY_WHITE, GENMOVE};
#include "qgtp.h"

#ifdef Q_WS_WIN
#include <Windows.h>
#endif

/* Function:  open a session
* Arguments: name and path of go program
* Fails:     never
* Returns:   nothing
*/
QGtp::QGtp()
{
	/*openGtpSession(filename);*/
	programProcess = NULL; // This to permit proper ending
	responseReceived = FALSE;
	answer = "";
}

QGtp::~QGtp()
{
	if (programProcess)
		programProcess->kill();     // not very clean (should use tryTerminate)
}

/* Code */

/* Function:  get the last message from gnugo
* Arguments: none
* Fails:     never
* Returns:   last message from GO
*/


QString QGtp::getLastMessage()
{
	return _response;
}

int QGtp::openGtpSession(QString filename, int size, float komi, int handicap, int /*level*/)
{
	_cpt = 1000;
	
	programProcess = new QProcess();
	QStringList arguments;
	issueCmdNb = FALSE;
	
	if(!filename.count())
	{
		_response = "No go engine path set";
		return FAIL;
	}

	if (filename.toLower().contains("gnugo"))
	{
		arguments << "--mode" << "gtp" << "--quiet" ;
		issueCmdNb = TRUE;
	}

	if (filename.toLower().contains("mogo"))
	{
		arguments << "--19" << "--dontDisplay" << "1" ;

	}


	connect(programProcess, SIGNAL(readyRead()),
		this, SLOT(slot_readFromStdout()) );
	connect(programProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
		this, SLOT(slot_processExited(int , QProcess::ExitStatus )) );
	
	qDebug("starting Go engine : %s %s", filename.toLatin1().constData(), arguments.join(" ").toLatin1().constData());

	programProcess->start(filename, arguments);

	

	if (!programProcess->waitForStarted())
	{
		  _response="Could not start "+filename;
		  return FAIL ;
	}
	
	//?? never know ... otherwise, I get a segfault with sprint ...
	if ((outFile = (char *)malloc (100)) == NULL)
	{
		  _response="Yuck ! Could not allocate 100 bytes !!!"  ;
		  return FAIL ;
	}   
	
	if (protocolVersion()==OK)
	{
		if(getLastMessage().toInt() !=2)
		{
			qDebug("Protocol version problem???");
			//				quit();
			_response="Protocol version not supported";
			//				return FAIL;
		}
		if(setBoardsize(size)==FAIL)
		{
			return FAIL;
		}
		if(clearBoard()==FAIL)
		{
			// removed by frosla -> protocol changes...
			// return FAIL;
		}

/*
		if(knownCommand("level")==FAIL)
		{
			  return FAIL;
		}
	
		else if (getLastMessage().contains("true"))
        	{
        		if (setLevel(level)==FAIL)
			{
				return FAIL;
			}
        	}
*/ 
      
		if(setKomi(komi)==FAIL)
		{
			return FAIL;
		}

		if(fixedHandicap(handicap)==FAIL)
		{
			return FAIL;
		}
	}
	else
	{
		quit();
		_response="Protocol version error";
		return FAIL;
	}

	return OK;
}

// Read from stdout
void QGtp::slot_readFromStdout()
{
	int number;
	int pos;

	QString s;
	do 
	{
		s = programProcess->readAllStandardOutput();
		answer.append(s); 
	} while (!s.isEmpty());
	if(answer[answer.length() - 1] != '\n')
		return;
	responseReceived = TRUE;
		
	answer=answer.trimmed();
	if (answer.length() != 0)
		_response = answer;
	answer = "";

	buff = _response[0];
	
	if(buff != "=" && buff != "?")
	{
		responseReceived = FALSE;
		return;
	}

	// do we have any answer after the command number ?
	pos = _response.indexOf(" ");
	number = _response.mid(1,pos).toInt();

	if (pos < 1)
		_response = "";
	else
		_response = _response.right(_response.length() - pos - 1);


	qDebug("** QGtp::slot_read():  \'%s\'" , _response.toLatin1().constData());

/*
	switch (number)
	{
		case GENMOVE:
			emit signal_computerPlayed( (buff != "?") , _response );
			responseReceived = FALSE;
		default:
			;
	}
*/
}

// exit
void QGtp::slot_processExited(int exitCode, QProcess::ExitStatus exitStatus)
{
	qDebug("Process Exited with exit code %i and status  %d", exitCode, exitStatus);
//	sprintf (outFile, "%d quit\n", _cpt);
//	sprintf (outFile, "quit\n");
//	fflush(outFile);
	//	return waitResponse();
}

/* Function:  wait for a go response
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::waitResponse()
{
	QString buf = _response;
	//	QTextStream * inFile;
	//	char symbole;
	//int number;
	//int pos;
	do //FIXME : we don't nned this, since the process sends the readyRead signal
	{
		qApp->processEvents();
/*#ifdef Q_WS_WIN
		Sleep(100000);
#else
		usleep(100000);
#endif
*/
	} while (!responseReceived/*_response.length() == 0 || _response == buf*/);
	/*
	inFile=new QTextStream(programProcess->readStdout(),IO_ReadOnly);
	do
	{
	* inFile>>symbole;
	* inFile>>number;
	buff=inFile->readLine();
	} while(number !=_cpt);
	*/
	
	//	_response=buff.stripWhiteSpace();
	
	/*	
	buff=programProcess->readLineStdout();
	while(!buff.isEmpty())
	{
	_response=_response+"\n"+buff;
	buff=programProcess->readLineStdout();
	}
	*/
	/*
	buff = _response[0];
	if ((pos = _response.indexOf(" ")) < 1)
		pos = 1;
	number = _response.mid(1,pos).toInt();
	_response = _response.right(_response.length() - pos - 1);
	*/
	qDebug("** QGtp::waitResponse():  \'%s\'" , _response.toLatin1().constData());
	responseReceived = FALSE;

	if (buff == "?") //symbole=='?')
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/****************************
* Program identity.        *
****************************/

/* Function:  Report the name of the program.
* Arguments: none
* Fails:     never
* Returns:   program name
*/
int
QGtp::name ()
{
	qDebug("%d name",_cpt);
	sprintf (outFile, "%d name\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Report protocol version.
* Arguments: none
* Fails:     never
* Returns:   protocol version number
*/
int
QGtp::protocolVersion ()
{
	qDebug("%d protocol_version",_cpt);
	if (issueCmdNb)
		sprintf (outFile, "%d protocol_version\n", /*_cpt*/ PROTOCOL);
	else
		sprintf (outFile, "protocol_version\n");
		
	fflush(outFile);
	return waitResponse();
}

void QGtp::fflush(char * s)
{
/*
int msglen = strlen(s);

  QByteArray dat(msglen);
  for (int j = 0; j < msglen; j++) {
  dat[j] = s[j];
  }
  programProcess->writeToStdin(dat);
	*/
	_cpt++;

	qDebug("flush -> %s",s);
	uint i= programProcess->write(QByteArray(s));

//	int j= programProcess->waitForBytesWritten ( 100 );

	if ( i != strlen(s)) 
		qDebug("Error writing %s",s);
	
	
}

/****************************
* Administrative commands. *
****************************/

/* Function:  Quit
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::quit ()
{
//	sprintf (outFile, "%d quit\n", _cpt);
	sprintf (outFile, "quit\n");
	fflush(outFile);
	return waitResponse();
}

/* Function:  Report the version number of the program.
* Arguments: none
* Fails:     never
* Returns:   version number
*/
int
QGtp::version ()
{
//	sprintf (outFile, "%d version\n", _cpt);
	sprintf (outFile,"version\n");
	fflush(outFile);
	return waitResponse();
}


/***************************
* Setting the board size. *
***************************/

/* Function:  Set the board size to NxN.
* Arguments: integer
* Fails:     board size outside engine's limits
* Returns:   nothing
*/
int
QGtp::setBoardsize (int size)
{
	if (issueCmdNb)
		sprintf (outFile, "%d boardsize %d\n", BOARDSIZE /*_cpt*/, size);
	else
		sprintf (outFile, "boardsize %d\n", size);
	fflush(outFile);
	return waitResponse();
}


/* Function:  Find the current boardsize
* Arguments: none
* Fails:     never
* Returns:   board_size
*/
int
QGtp::queryBoardsize()
{
	sprintf (outFile, "%d query_boardsize\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/***********************
* Clearing the board. *
***********************/

/* Function:  Clear the board.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/

int
QGtp::clearBoard ()
{
//	if (issueCmdNb)
//		sprintf (outFile, "%d clear_board\n", _cpt);
//	else
		sprintf (outFile,"clear_board\n");
	fflush(outFile);
	return waitResponse();
}

/***************************
* Setting.           *
***************************/

/* Function:  Set the komi.
* Arguments: float
* Fails:     incorrect argument
* Returns:   nothing
*/
int
QGtp::setKomi(float f)
{
	if (issueCmdNb)
		sprintf (outFile, "%d komi %.2f\n", KOMI /*_cpt*/,f);
	else
		sprintf (outFile, "komi %.2f\n", f);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Set the playing level.
* Arguments: int
* Fails:     incorrect argument
* Returns:   nothing
*/
int
QGtp::setLevel (int level)
{
	sprintf (outFile, "%d level %d\n", _cpt,level);
	fflush(outFile);
	return waitResponse();
}
/******************
* Playing moves. *
******************/

/* Function:  Play a black stone at the given vertex.
* Arguments: vertex
* Fails:     invalid vertex, illegal move
* Returns:   nothing
*/
int
QGtp::playblack (char c , int i)
{
	//  sprintf (outFile, "%d play black %c%d\n", _cpt,c,i);
	if (issueCmdNb)
		sprintf (outFile, "%d play black %c%d\n", PLAY_BLACK/*_cpt*/,c,i);
	else
		sprintf (outFile, "play black %c%d\n", c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Black pass.
* Arguments: None
* Fails:     never
* Returns:   nothing
*/
int
QGtp::playblackPass ()
{
	//  sprintf (outFile, "%d play black pass\n", _cpt);
	if (issueCmdNb)
		sprintf (outFile, "%d play black pass\n", PLAY_BLACK /*_cpt*/);
	else
		sprintf (outFile, "play black pass\n");
	fflush(outFile);
	return waitResponse();
}

/* Function:  Play a white stone at the given vertex.
* Arguments: vertex
* Fails:     invalid vertex, illegal move
* Returns:   nothing
*/
int
QGtp::playwhite (char c, int i)
{
	//  sprintf (outFile, "%d play white %c%d\n", _cpt,c,i);
	if (issueCmdNb)
		sprintf (outFile, "%d play white %c%d\n", PLAY_WHITE /*_cpt*/,c,i);
	else
		sprintf (outFile, "play white %c%d\n", c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  White pass.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::playwhitePass ()
{
	//  sprintf (outFile, "%d play white pass\n", _cpt);
	if (issueCmdNb)
		sprintf (outFile, "%d play white pass\n",PLAY_WHITE /*_cpt*/);
	else
		sprintf (outFile, "play white pass\n");
	fflush(outFile);
	return waitResponse();
}

/* Function:  Set up fixed placement handicap stones.
* Arguments: number of handicap stones
* Fails:     invalid number of stones for the current boardsize
* Returns:   list of vertices with handicap stones
*/
int
QGtp::fixedHandicap (int handicap)
{
	if (handicap < 2) 
		return OK;

	if (issueCmdNb)
		sprintf (outFile, "%d fixed_handicap %d\n", _cpt,handicap);
	else
		sprintf (outFile, "fixed_handicap %d\n",handicap);

	fflush(outFile);
	return waitResponse();
}

/* Function:  Load an sgf file, possibly up to a move number or the first
*            occurence of a move.
* Arguments: filename + move number, vertex, or nothing
* Fails:     missing filename or failure to open or parse file
* Returns:   color to play
*/
int QGtp::loadsgf (QString filename,int /*movNumber*/,char /*c*/,int /*i*/)
{
	//sprintf (outFile, "%d loadsgf %s %d %c%d\n", _cpt,(const char *) filename,movNumber,c,i);
	qDebug("**QGtp::loadsgf : loading file %s", filename.toLatin1().constData());
	sprintf (outFile, "%d loadsgf %s\n", _cpt,filename.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/*****************
* Board status. *
*****************/

/* Function:  Return the color at a vertex.
* Arguments: vertex
* Fails:     invalid vertex
* Returns:   "black", "white", or "empty"
*/
int
QGtp::whatColor (char c, int i)
{
	sprintf (outFile, "%d color %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Count number of liberties for the string at a vertex.
* Arguments: vertex
* Fails:     invalid vertex, empty vertex
* Returns:   Number of liberties.
*/
int
QGtp::countlib (char c, int i)
{
	sprintf (outFile, "%d countlib %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Return the positions of the liberties for the string at a vertex.
* Arguments: vertex
* Fails:     invalid vertex, empty vertex
* Returns:   Sorted space separated list of vertices.
*/
int
QGtp::findlib (char c, int i)
{
	sprintf (outFile, "%d findlib %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Tell whether a move is legal.
* Arguments: move
* Fails:     invalid move
* Returns:   1 if the move is legal, 0 if it is not.
*/
int
QGtp::isLegal (QString color, char c, int i)
{
	sprintf (outFile, "%d is_legal %s %c%d\n", _cpt,color.toLatin1().constData(),c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  List all legal moves for either color.
* Arguments: color
* Fails:     invalid color
* Returns:   Sorted space separated list of vertices.
*/
int
QGtp::allLegal (QString color)
{
	sprintf (outFile, "%d all_legal %s\n", _cpt,color.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/* Function:  List the number of captures taken by either color.
* Arguments: color
* Fails:     invalid color
* Returns:   Number of captures.
*/
int
QGtp::captures (QString color)
{
	sprintf (outFile, "%d captures %s\n", _cpt,color.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/**********************
* Retractable moves. *
**********************/

/* Function:  Play a stone of the given color at the given vertex.
* Arguments: move (color + vertex)
* Fails:     invalid color, invalid vertex, illegal move
* Returns:   nothing
*/
int
QGtp::trymove (QString color, char c, int i)
{
	sprintf (outFile, "%d trymove %s %c%d\n", _cpt,color.toLatin1().constData(),c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Undo a trymove.
* Arguments: none
* Fails:     stack empty
* Returns:   nothing
*/
int
QGtp::popgo ()
{
	sprintf (outFile, "%d popgo\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/*********************
* Tactical reading. *
*********************/

/* Function:  Try to attack a string.
* Arguments: vertex
* Fails:     invalid vertex, empty vertex
* Returns:   attack code followed by attack point if attack code nonzero.
*/
int
QGtp::attack (char c, int i)
{
	sprintf (outFile, "%d attack %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Try to defend a string.
* Arguments: vertex
* Fails:     invalid vertex, empty vertex
* Returns:   defense code followed by defense point if defense code nonzero.
*/
int
QGtp::defend (char c, int i)
{
	sprintf (outFile, "%d defend %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Increase depth values by one.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::increaseDepths ()
{
	sprintf (outFile, "%d increase_depths\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Decrease depth values by one.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::decreaseDepths ()
{
	sprintf (outFile, "%d decrease_depths\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/******************
* owl reading. *
******************/

/* Function:  Try to attack a dragon.
* Arguments: vertex
* Fails:     invalid vertex, empty vertex
* Returns:   attack code followed by attack point if attack code nonzero.
*/
int
QGtp::owlAttack (char c, int i)
{
	sprintf (outFile, "%d owl_attack %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Try to defend a dragon.
* Arguments: vertex
* Fails:     invalid vertex, empty vertex
* Returns:   defense code followed by defense point if defense code nonzero.
*/
int
QGtp::owlDefend (char c, int i)
{
	sprintf (outFile, "%d owl_defend %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/********
* eyes *
********/

/* Function:  Evaluate an eye space
* Arguments: vertex
* Fails:     invalid vertex
* Returns:   Minimum and maximum number of eyes. If these differ an
*            attack and a defense point are additionally returned.
*            If the vertex is not an eye space or not of unique color,
*            a single -1 is returned.
*/

int
QGtp::evalEye (char c, int i)
{
	sprintf (outFile, "%d eval_eye %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/*****************
* dragon status *
*****************/

/* Function:  Determine status of a dragon.
* Arguments: vertex
* Fails:     invalid vertex, empty vertex
* Returns:   status ("alive", "critical", "dead", or "unknown"),
*            attack point, defense point. Points of attack and
*            defense are only given if the status is critical and the
*            owl code is enabled.
*
* FIXME: Should be able to distinguish between life in seki
*        and life with territory. Should also be able to identify ko.
*/

int
QGtp::dragonStatus (char c, int i)
{
	sprintf (outFile, "%d dragon_status %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Determine whether two stones belong to the same dragon.
* Arguments: vertex, vertex
* Fails:     invalid vertex, empty vertex
* Returns:   1 if the vertices belong to the same dragon, 0 otherwise
*/

int
QGtp::sameDragon (char c1, int i1, char c2, int i2)
{
	sprintf (outFile, "%d same_dragon %c%d %c%d\n", _cpt,c1,i1,c2,i2);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Return the information in the dragon data structure.
* Arguments: nothing
* Fails:     never
* Returns:   Dragon data formatted in the corresponding way to gtp_worm__
*/
int
QGtp::dragonData ()
{
	sprintf (outFile, "%d dragon_data \n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Return the information in the dragon data structure.
* Arguments: intersection
* Fails:     invalid coordinate
* Returns:   Dragon data formatted in the corresponding way to gtp_worm__
*/
int
QGtp::dragonData (char c,int i)
{
	sprintf (outFile, "%d dragon_data %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/***********************
* combination attacks *
***********************/

/* Function:  Find a move by color capturing something through a
*            combination attack.
* Arguments: color
* Fails:     invalid color
* Returns:   Recommended move, PASS if no move found
*/

int
QGtp::combinationAttack (QString color)
{
	sprintf (outFile, "%d combination_attack %s\n", _cpt,color.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/********************
* generating moves *
********************/

/* Function:  Generate and play the supposedly best black move.
* Arguments: none
* Fails:     never
* Returns:   a move coordinate (or "PASS")
*/
int
QGtp::genmoveBlack ()
{
	if (issueCmdNb)
		sprintf (outFile, "%d genmove black\n", GENMOVE);
	else
		sprintf (outFile, "genmove black\n");
	fflush(outFile);
	waitResponse();

	emit signal_computerPlayed( (buff != "?") , _response );
//	responseReceived = FALSE;

	return OK;
}

/* Function:  Generate and play the supposedly best white move.
* Arguments: none
* Fails:     never
* Returns:   a move coordinate (or "PASS")
*/
int
QGtp::genmoveWhite ()
{
	if (issueCmdNb)
		sprintf (outFile, "%d genmove white\n", GENMOVE);
	else
		sprintf (outFile, "genmove white\n");
	fflush(outFile);
	waitResponse();

	emit signal_computerPlayed( (buff != "?") , _response );
//	responseReceived = FALSE;

	return OK;
}

/* Function:  Generate the supposedly best move for either color.
* Arguments: color to move, optionally a random seed
* Fails:     invalid color
* Returns:   a move coordinate (or "PASS")
*/
int
QGtp::genmove (QString color,int seed)
{
	sprintf (outFile, "%d gg_genmove %s %d\n", _cpt,color.toLatin1().constData(),seed);
	fflush(outFile);
	return waitResponse();
}

/* Function : Generate a list of the best moves for White with weights
* Arguments: none
* Fails:   : never
* Returns  : list of moves with weights
*/

int
QGtp::topMovesWhite ()
{
	sprintf (outFile, "%d top_moves_white\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function : Generate a list of the best moves for Black with weights
* Arguments: none
* Fails:   : never
* Returns  : list of moves with weights
*/

int
QGtp::topMovesBlack ()
{
	sprintf (outFile, "%d top_moves_black\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Undo last move
* Arguments: int
* Fails:     If move pointer is 0
* Returns:   nothing
*/
int
QGtp::undo (int i)
{
	sprintf (outFile, "%d undo %d\n", _cpt,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Report the final status of a vertex in a finished game.
* Arguments: Vertex, optional random seed
* Fails:     invalid vertex
* Returns:   Status in the form of one of the strings "alive", "dead",
*            "seki", "white_territory", "black_territory", or "dame".
*/
int
QGtp::finalStatus (char c, int i, int seed)	
{
	sprintf (outFile, "%d final_status %c%d %d\n", _cpt,c,i,seed);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Report vertices with a specific final status in a finished game.
* Arguments: Status in the form of one of the strings "alive", "dead",
*            "seki", "white_territory", "black_territory", or "dame".
*            An optional random seed can be added.
* Fails:     missing or invalid status string
* Returns:   Vertices having the specified status. These are split with
*            one string on each line if the vertices are nonempty (i.e.
*            for "alive", "dead", and "seki").
*/
int
QGtp::finalStatusList (QString status, int seed)
{
	sprintf (outFile, "%d final_status_list %s %d\n", _cpt,status.toLatin1().constData(),seed);
	fflush(outFile);
	return waitResponse();
}

/**************
* score *
**************/

/* Function:  Compute the score of a finished game.
* Arguments: Optional random seed
* Fails:     never
* Returns:   Score in SGF format (RE property).
*/
int
QGtp::finalScore (int seed)
{
	sprintf (outFile, "%d final_score %d\n", _cpt,seed);
	fflush(outFile);
	return waitResponse();
}

int
QGtp::estimateScore ()
{
	sprintf (outFile, "%d estimate_score\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

int
QGtp::newScore ()
{
	sprintf (outFile, "%d new_score \n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/**************
* statistics *
**************/

/* Function:  Reset the count of life nodes.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::resetLifeNodeCounter ()
{
	sprintf (outFile, "%d reset_life_node_counter\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Retrieve the count of life nodes.
* Arguments: none
* Fails:     never
* Returns:   number of life nodes
*/
int
QGtp::getLifeNodeCounter ()
{
	sprintf (outFile, "%d get_life_node_counter\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Reset the count of owl nodes.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::resetOwlNodeCounter ()
{
	sprintf (outFile, "%d reset_owl_node_counter\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Retrieve the count of owl nodes.
* Arguments: none
* Fails:     never
* Returns:   number of owl nodes
*/
int
QGtp::getOwlNodeCounter ()
{
	sprintf (outFile, "%d get_owl_node_counter\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Reset the count of reading nodes.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::resetReadingNodeCounter ()
{
	sprintf (outFile, "%d reset_reading_node_counter\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Retrieve the count of reading nodes.
* Arguments: none
* Fails:     never
* Returns:   number of reading nodes
*/
int
QGtp::getReadingNodeCounter ()
{
	sprintf (outFile, "%d get_reading_node_counter\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Reset the count of trymoves/trykos.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::resetTrymoveCounter ()
{
	sprintf (outFile, "%d reset_trymove_counter\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Retrieve the count of trymoves/trykos.
* Arguments: none
* Fails:     never
* Returns:   number of trymoves/trykos
*/
int
QGtp::getTrymoveCounter ()
{
	sprintf (outFile, "%d get_trymove_counter\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/*********
* debug *
*********/

/* Function:  Write the position to stderr.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::showboard ()
{
	sprintf (outFile, "%d showboard\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Dump stack to stderr.
* Arguments: none
* Fails:     never
* Returns:   nothing
*/
int
QGtp::dumpStack ()
{
	sprintf (outFile, "%d dump_stack\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Write information about the influence function to stderr.
* Arguments: color to move, optionally a list of what to show
* Fails:     invalid color
* Returns:   nothing
*/
int
QGtp::debugInfluence (QString color,QString list)
{
	sprintf (outFile, "%d debug_influence %s %s\n", _cpt,color.toLatin1().constData(),list.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/* Function:  Write information about the influence function after making
*            a move to stderr.
* Arguments: move, optionally a list of what to show
* Fails:     never
* Returns:   nothing
*/
int
QGtp::debugMoveInfluence (QString color, char c, int i,QString list)
{
	sprintf (outFile, "%d debug_move_influence %s %c%d %s\n", _cpt,color.toLatin1().constData(),c,i,list.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/* Function:  Return information about the influence function.
* Arguments: color to move
* Fails:     never
* Returns:   Influence data formatted
*/
int
QGtp::influence (QString color)
{
	sprintf (outFile, "%d influence %s\n", _cpt,color.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/* Function:  Return information about the influence function after a move
* Arguments: move
* Fails:     never
* Returns:   Influence data formatted in the same way as for gtp_influence.
*/
int
QGtp::moveInfluence (QString color, char c, int i)
{
	sprintf (outFile, "%d move_influence %s %c%d\n", _cpt,color.toLatin1().constData(),c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Return the information in the worm data structure.
* Arguments: none
* Fails:     never
* Returns:   Worm data formatted
*/
int
QGtp::wormData ()
{
	sprintf (outFile, "%d worm_data\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Return the information in the worm data structure.
* Arguments: vertex
* Fails:     never
* Returns:   Worm data formatted
*/
int
QGtp::wormData (char c, int i)
{
	sprintf (outFile, "%d worm_data %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Return the cutstone field in the worm data structure.
* Arguments: non-empty vertex
* Fails:     never
* Returns:   cutstone
*/
int
QGtp::wormCutstone (char c, int i)
{
	sprintf (outFile, "%d worm_cutstone %c%d\n", _cpt,c,i);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Tune the parameters for the move ordering in the tactical
*            reading.
* Arguments: MOVE_ORDERING_PARAMETERS integers
* Fails:     incorrect arguments
* Returns:   nothing
*/
int
QGtp::tuneMoveOrdering (int MOVE_ORDERING_PARAMETERS)
{
	sprintf (outFile, "%d tune_move_ordering %d\n", _cpt,MOVE_ORDERING_PARAMETERS);
	fflush(outFile);
	return waitResponse();
}

/* Function:  Echo the parameter
* Arguments: string
* Fails:     never
* Returns:   nothing
*/
int
QGtp::echo (QString param)
{
	sprintf (outFile, "%d echo %s\n", _cpt,param.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/* Function:  List all known commands
* Arguments: none
* Fails:     never
* Returns:   list of known commands, one per line
*/
int
QGtp::help ()
{
	sprintf (outFile, "%d help\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

/* Function:  evaluate wether a command is known
* Arguments: command word
* Fails:     never
* Returns:   true or false
*/
int
QGtp::knownCommand (QString s)
{
	sprintf (outFile, "%d known_command %s\n", _cpt,s.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/* Function:  Turn uncertainty reports from owl_attack
*            and owl_defend on or off.
* Arguments: "on" or "off"
* Fails:     invalid argument
* Returns:   nothing
*/
int
QGtp::reportUncertainty (QString s)
{
	sprintf (outFile, "%d report_uncertainty %s\n", _cpt,s.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

/* Function:  List the stones of a worm
* Arguments: the location
* Fails:     if called on an empty or off-board location
* Returns:   list of stones
*/
int
QGtp::wormStones()
{
	sprintf (outFile, "%d worm_stones\n", _cpt);
	fflush(outFile);
	return waitResponse();
}

int
QGtp::shell(QString s)
{
	sprintf (outFile, "%d %s\n", _cpt, s.toLatin1().constData());
	fflush(outFile);
	return waitResponse();
}

