/*
Programa que permite jugar ajedrez en una consola

Las columnas del tablero están etiquetadas con las letras 'a' hasta la 'h'. Correspondiendo
a la letra 'a' la columna más a la izquierda en la posicion de las piezas blancas.

Las filas del tablero están etiquetadas con los números '1' hasta '8' y van en orden ascendente
desde la posicion inicial de las piezas blancas.

Se presenta un tablero en modo texto, sobre el que se pueden realizar jugadas en la forma
algebraica:

o-o para el enroque corto
o-o-o para el enroque largo
xn-ym para otros movimientos, donde:
	
	x: letra de la columna inicial de la pieza (va desde 'a' para la primera columna, hasta
		'h' para la octava columna)
	n: numero para la fila inicial de la pieza (va desde '1' para la primera fila, hasta
		'8' para la octava fila)
	y: letra de la columna final de la pieza (va desde 'a' para la primera columna, hasta
		'h' para la octava columna)
	m: numero para la fila final de la pieza (va desde '1' para la primera fila, hasta
		'8' para la octava fila)

Movimiento de ejemplo: e2-e4, mover la pieza en la columna 'e', fila '2', hasta la casilla
ubicada en la columna 'e', fila '4'.

Si se tratara de un peon que se mueve a la octava fila (peón coronado), agregar al movimiento
el carácter '=' seguido de una de las siguientes letras:
'b' para convertirlo en alfil
'h' para convertirlo en caballo
'q' para convertirlo en dama
'c' para convertirlo en torre

Ejemplo: d7-d8=q, mover el peon en d7 a la casilla d8 y convertirlo en dama.

El símbolo 'x' para el cambio de piezas debe ser reemplazado por el símbolo '-'. Ejemplo:
'e4xd5' se debe convertir a 'e4-d5' (mover la pieza en 'e4' a 'd5', si hay una pieza en la casilla
final, capturarla).

Si se quiere proponer tablas sólo ponga como jugada el símbolo '-' (empate).
Para aceptar la propuesta de tablas ponga el símbolo '=', para rechazarla '#'.

Si se va a rendir sólo ponga en la jugada el símbolo '/' (abandonar, tirar al rey).

Este programa debe reconocer:

- Tablas por repeticion de jugadas
- Tablas por rey ahogado
- Jaque
- Jaque mate
- Peon coronado
- Captura de peon al paso
- Enroque corto y largo
y el resto de los posibles movimientos de cada una de las piezas.

En caso de algún error en el programa, favor de informarlo para corregirlo.

Atte. 
		I.S.C. Ariel Medina - Campeche, Campeche, México - Diciembre del 2003

//******
Informe técnico

	El tablero es una matriz de apuntadores a objetos de una clase polimórfica. Dicha
	clase se llama piece y contiene la interfaz común para todas las piezas de ajedrez,
	como son las funciones:

		getColor(), para obtener el color de la pieza
		virtual clone(), necesaria para la replicación de objetos sin pérdida de información

		virtual move(), para mover una pieza a determinada posición
		virtual getPositions(), para obtener las posiciones a las que puede mover una pieza

	Estas últimas funciones son virtuales porque cada pieza mueve en forma diferente y puede
	moverse	a posiciones que dependen de su naturaleza y de la posicion de las demás.

	Esta clase también define las características de las piezas, como son ataque vertical,
	horizontal, diagonal, mover sólo hacia adelante, y sólo una casilla.

	piece es la clase base para las clases pawn, bishop, knight, castle, queen y king; que son
	las piezas bien definidas del juego.

	Se hace uso del evaluador de expressiones regulares para decidir si la cadena que el usuario
	pasa al objeto es una jugada válida.

//******

*/

#include <iostream>
#include <list>
#include "matrix.h"
#include "deque.h"
#include "stringAMV.h"
#include "mathAMV.h"
#include "pointer.h"
#include "REEvaluator.h"

namespace amv	{

struct position	{
	int row,col;
	position(): row(0), col(0)
		{
		}
	position(int r, int c): row(r), col(c)
		{
		}
	bool operator==(const position &p) const
		{
		return (row==p.row && col==p.col);
		}

};

enum piece_type	{ KNIGHT, KING, QUEEN, BISHOP, PAWN, CASTLE };

class round;

class piece	{
	public:
		//constantes para ataque horizontal,vertical,diagonal y en L. También para sólo avanzar
		static const unsigned int hAttack, vAttack, dAttack, lAttack, onlyForward, onlyOneSquare;
		const unsigned int traits;

		piece_type pt;
		position pos;
		int value;
		//poner tal vez un valor en funcion de las piezas atacadas y defendidas
		char letter;
		bool color;
		bool moved;
		//std::list<piece *> attackTo;
		matrix<ipointer<piece> > *pChessboard;

		piece(piece_type t, const position &p, int v, char l, bool c, matrix<ipointer<piece> > *pCb, const unsigned int tr):
		pt(t), pos(p), value(v), letter(l), color(c), pChessboard(pCb), traits(tr), moved(false)
			{
			}

		virtual piece *clone() const
			{
			return new piece(*this);
			}
		void setChessboard(matrix<ipointer<piece> > *pCb)
			{
			pChessboard=pCb;
			}

		virtual bool move(const position &newPos)
			{
			(*pChessboard)[newPos.row][newPos.col]=this;
			(*pChessboard)[pos.row][pos.col].untie();
			pos=newPos;
			if(!moved)
				moved=true;

			return true;
			}
		bool capture(const position &newPos)
			{
			(*pChessboard)[newPos.row][newPos.col]=ipointer<piece>();//liberamos la pieza
			return piece::move(newPos);
			}
		virtual void getPositions(deque<position> &dp) const
			{
			
			}

		void gethPositions(deque<position> &dp) const
			{
			int i;

			//horizontal
			for(i=pos.col+1; i<(*pChessboard).columns(); ++i)
				{
				if((*pChessboard)[pos.row][i])
					{
					if((*pChessboard)[pos.row][i]->getColor()!=getColor())
						dp.push_back(position(pos.row,i));
					break;
					}
				else
					dp.push_back(position(pos.row,i));
				}
			for(i=pos.col-1; i>=0; --i)
				{
				if((*pChessboard)[pos.row][i])
					{
					if((*pChessboard)[pos.row][i]->getColor()!=getColor())
						dp.push_back(position(pos.row,i));
					break;
					}
				else
					dp.push_back(position(pos.row,i));
				}			
			}

		void getvPositions(deque<position> &dp) const
			{
			int i;

			//vertical
			for(i=pos.row+1; i<(*pChessboard).rows(); ++i)
				{
				if((*pChessboard)[i][pos.col])
					{
					if((*pChessboard)[i][pos.col]->getColor()!=getColor())
						dp.push_back(position(i,pos.col));
					break;
					}
				else
					dp.push_back(position(i,pos.col));
				}
			for(i=pos.row-1; i>=0; --i)
				{
				if((*pChessboard)[i][pos.col])
					{
					if((*pChessboard)[i][pos.col]->getColor()!=getColor())
						dp.push_back(position(i,pos.col));
					break;
					}
				else
					dp.push_back(position(i,pos.col));
				}
			
			}

		void getdPositions(deque<position> &dp) const
			{
			int i,j;

			//diagonal
			for(i=pos.row+1, j=pos.col+1; i<(*pChessboard).rows() && j<pChessboard->columns(); ++i, ++j)
				if((*pChessboard)[i][j])
					{
					if((*pChessboard)[i][j]->getColor()!=getColor())
						dp.push_back(position(i,j));
					break;
					}
				else
					dp.push_back(position(i,j));

			for(i=pos.row-1, j=pos.col+1; i>=0 && j<pChessboard->columns(); --i, ++j)
				if((*pChessboard)[i][j])
					{
					if((*pChessboard)[i][j]->getColor()!=getColor())
						dp.push_back(position(i,j));
					break;
					}
				else
					dp.push_back(position(i,j));

			for(i=pos.row+1, j=pos.col-1; i<(*pChessboard).rows() && j>=0; ++i, --j)
				if((*pChessboard)[i][j])
					{
					if((*pChessboard)[i][j]->getColor()!=getColor())
						dp.push_back(position(i,j));
					break;
					}
				else
					dp.push_back(position(i,j));

			for(i=pos.row-1, j=pos.col-1; i>=0 && j>=0; --i, --j)
				if((*pChessboard)[i][j])
					{
					if((*pChessboard)[i][j]->getColor()!=getColor())
						dp.push_back(position(i,j));
					break;
					}
				else
					dp.push_back(position(i,j));
			
			}
			
		virtual void revalue()
			{
			}
		bool getColor() const
			{
			return color;
			}
		bool isValidPosition(const position &p) const
			{
			if(p.row<0 || p.row>=pChessboard->rows())
				return false;
			if(p.col<0 || p.col>=pChessboard->columns())
				return false;

			return true;
			}

		bool isPieceBetween(const position &p)
			{
			int i,j;
			if(p.col==pos.col)//vertical
				{
				if(pos.row>p.row)
					{
					for(i=p.row+1; i<pos.row; ++i)
						if((*pChessboard)[i][pos.col])
							return true;
					}
				else
					{
					for(i=pos.row+1; i<p.row; ++i)
						if((*pChessboard)[i][pos.col])
							return true;
					}

				return false;
				}
			if(p.row==pos.row)//horizontal
				{
				if(pos.col>p.col)
					{
					for(i=p.col+1; i<pos.col; ++i)
						if((*pChessboard)[pos.row][i])
							return true;
					}
				else
					{
					for(i=pos.col+1; i<p.col; ++i)
						if((*pChessboard)[pos.row][i])
							return true;
					}

				return false;
				}
			if(abs(p.row-pos.row)==abs(p.col-pos.col))//diagonal
				{
				if(p.col>pos.col)
					{
					if(p.row>pos.row)
						{
						for(i=pos.row+1, j=pos.col+1; i<p.row; ++i, ++j)
							if((*pChessboard)[i][j])
								return true;
						}
					else
						{
						for(i=pos.row-1, j=pos.col+1; i>p.row; --i, ++j)
							if((*pChessboard)[i][j])
								return true;
						}
					}
				else
					{
					if(p.row>pos.row)
						{
						for(i=pos.row+1, j=pos.col-1; i<p.row; ++i, --j)
							if((*pChessboard)[i][j])
								return true;
						}
					else
						{
						for(i=pos.row-1, j=pos.col-1; i>p.row; --i, --j)
							if((*pChessboard)[i][j])
								return true;
						}
					}

				return false;
				}

			return false;
			}
		bool isAttacked()
			{
			int i,j;

			//ataque vertical
			for(i=pos.row+1; i<(*pChessboard).rows(); ++i)
				if((*pChessboard)[i][pos.col])
					if((*pChessboard)[i][pos.col]->getColor()!=getColor())
						{
						if((*pChessboard)[i][pos.col]->traits & piece::vAttack)
							return true;
						else
							break;
						}
					else
						break;
			for(i=pos.row-1; i>=0; --i)
				if((*pChessboard)[i][pos.col])
					if((*pChessboard)[i][pos.col]->getColor()!=getColor())
						{
						if((*pChessboard)[i][pos.col]->traits & piece::vAttack)
							return true;
						else
							break;
						}
					else
						break;

			//ataque horizontal
			for(i=pos.col+1; i<(*pChessboard).columns(); ++i)
				if((*pChessboard)[pos.row][i])
					if((*pChessboard)[pos.row][i]->getColor()!=getColor())
						{
						if((*pChessboard)[pos.row][i]->traits & piece::hAttack)
							return true;
						else
							break;
						}
					else
						break;
			for(i=pos.col-1; i>=0; --i)
				if((*pChessboard)[pos.row][i])
					if((*pChessboard)[pos.row][i]->getColor()!=getColor())
						{
						if((*pChessboard)[pos.row][i]->traits & piece::hAttack)
							return true;
						else
							break;
						}
					else
						break;

			//ataque en diagonal

			for(i=pos.row+1, j=pos.col+1; i<(*pChessboard).rows() && j<pChessboard->columns(); ++i, ++j)
				if((*pChessboard)[i][j])
					if((*pChessboard)[i][j]->getColor()!=getColor())
						{
						if(getColor())
							{//si es un peon
							if(((*pChessboard)[i][j]->traits & piece::dAttack)
								&& ((*pChessboard)[i][j]->traits & piece::onlyForward)
								&& ((*pChessboard)[i][j]->traits & piece::onlyOneSquare))
								{
								if(i-pos.row==1)
									return true;
								else
									break;
								}
							else
								if(((*pChessboard)[i][j]->traits & piece::dAttack))
									return true;
								else
									break;
							}
						else
							{
							if(((*pChessboard)[i][j]->traits & piece::dAttack)
								&& ((*pChessboard)[i][j]->traits & piece::onlyForward)
								&& ((*pChessboard)[i][j]->traits & piece::onlyOneSquare))
								{
								break;
								}
							else
								if(((*pChessboard)[i][j]->traits & piece::dAttack))
									return true;
								else
									break;
							}
						}
					else
						break;

			for(i=pos.row-1, j=pos.col+1; i>=0 && j<pChessboard->columns(); --i, ++j)
				if((*pChessboard)[i][j])
					if((*pChessboard)[i][j]->getColor()!=getColor())
						{
						if(getColor())
							{
							if(((*pChessboard)[i][j]->traits & piece::dAttack)
								&& ((*pChessboard)[i][j]->traits & piece::onlyForward)
								&& ((*pChessboard)[i][j]->traits & piece::onlyOneSquare))
								{
								break;
								}
							else
								if(((*pChessboard)[i][j]->traits & piece::dAttack))
									return true;
								else
									break;
							}
						else
							{
							if(((*pChessboard)[i][j]->traits & piece::dAttack)
								&& ((*pChessboard)[i][j]->traits & piece::onlyForward)
								&& ((*pChessboard)[i][j]->traits & piece::onlyOneSquare))
								{
								if(pos.row-i==1)
									return true;
								else
									break;
								}
							else
								if(((*pChessboard)[i][j]->traits & piece::dAttack))
									return true;
								else
									break;
							}

						}
					else
						break;

			for(i=pos.row+1, j=pos.col-1; i<(*pChessboard).rows() && j>=0; ++i, --j)
				if((*pChessboard)[i][j])
					if((*pChessboard)[i][j]->getColor()!=getColor())
						{
						if(getColor())
							{
							if(((*pChessboard)[i][j]->traits & piece::dAttack)
								&& ((*pChessboard)[i][j]->traits & piece::onlyForward)
								&& ((*pChessboard)[i][j]->traits & piece::onlyOneSquare))
								{
								if(i-pos.row==1)
									return true;
								else
									break;
								}
							else
								if(((*pChessboard)[i][j]->traits & piece::dAttack))
									return true;
								else
									break;
							}
						else
							{
							if(((*pChessboard)[i][j]->traits & piece::dAttack)
								&& ((*pChessboard)[i][j]->traits & piece::onlyForward)
								&& ((*pChessboard)[i][j]->traits & piece::onlyOneSquare))
								{
								break;
								}
							else
								if(((*pChessboard)[i][j]->traits & piece::dAttack))
									return true;
								else
									break;

							}

						}
					else
						break;

			for(i=pos.row-1, j=pos.col-1; i>=0 && j>=0; --i, --j)
				if((*pChessboard)[i][j])
					if((*pChessboard)[i][j]->getColor()!=getColor())
						{
						if(getColor())
							{
							if(((*pChessboard)[i][j]->traits & piece::dAttack)
								&& ((*pChessboard)[i][j]->traits & piece::onlyForward)
								&& ((*pChessboard)[i][j]->traits & piece::onlyOneSquare))
								{
								break;
								}
							else
								if(((*pChessboard)[i][j]->traits & piece::dAttack))
									return true;
								else
									break;
							}
						else
							{
							if(((*pChessboard)[i][j]->traits & piece::dAttack)
								&& ((*pChessboard)[i][j]->traits & piece::onlyForward)
								&& ((*pChessboard)[i][j]->traits & piece::onlyOneSquare))
								{
								if(pos.row-i==1)
									return true;
								else
									break;
								}
							else
								if(((*pChessboard)[i][j]->traits & piece::dAttack))
									return true;
								else
									break;
							}

						}
					else
						break;

			//ataque en L
			position lPositions[8];
			lPositions[0]=position(pos.row+2,pos.col+1);
			lPositions[1]=position(pos.row+1,pos.col+2);
			lPositions[2]=position(pos.row-1,pos.col+2);
			lPositions[3]=position(pos.row-2,pos.col+1);
			lPositions[4]=position(pos.row-2,pos.col-1);
			lPositions[5]=position(pos.row-1,pos.col-2);
			lPositions[6]=position(pos.row+1,pos.col-2);
			lPositions[7]=position(pos.row+2,pos.col-1);

			for(i=0; i<8; ++i)
				{
				if(isValidPosition(lPositions[i]))
					if((*pChessboard)[lPositions[i].row][lPositions[i].col])
						if((*pChessboard)[lPositions[i].row][lPositions[i].col]->getColor()!=getColor() && ((*pChessboard)[lPositions[i].row][lPositions[i].col]->traits & piece::lAttack))
							return true;
				}

			return false;
			}

		friend ostream &operator<<(ostream &os, const piece &p)
			{
			return os<<p.letter;
			}
};

const unsigned int piece::hAttack=0x0001, piece::vAttack=0x0002,
piece::dAttack=0x0004, piece::lAttack=0x0008, piece::onlyForward=0x0010, piece::onlyOneSquare=0x0020;

struct movement	{
ipointer<piece> pPiece;
position pos1,pos2;
	movement(): pPiece(), pos1(), pos2()
		{
		}
	movement(const ipointer<piece> &pP, const position &p1, const position &p2):
	pPiece(pP), pos1(p1), pos2(p2)
		{
		}

};

class bishop: public piece	{
	public:
		bishop(bool color, const position &p, matrix<ipointer<piece> > *pCb): piece(BISHOP,p,3,color? 'B': 'b', color,pCb,piece::dAttack)
			{
			}

		piece *clone() const
			{
			return new bishop(*this);
			}

		bool move(const position &newPos)
			{
			int colDif=abs(newPos.col-pos.col);
			int rowDif=abs(newPos.row-pos.row);
			if(rowDif==colDif)
				{
				if(isPieceBetween(newPos))
					return false;

				if((*pChessboard)[newPos.row][newPos.col])
					{
					return capture(newPos);
					}
				else
					{
					return piece::move(newPos);
					}
				}
			else
				return false;
			}

		void getPositions(deque<position> &dp) const
			{
			getdPositions(dp);
			}

};

class knight: public piece	{
	public:
		knight(bool color, const position &p, matrix<ipointer<piece> > *pCb): piece(KNIGHT,p,3,color? 'H': 'h', color,pCb,piece::lAttack)
			{
			}

		piece *clone() const
			{
			return new knight(*this);
			}

		bool move(const position &newPos)
			{
			int colDif=abs(newPos.col-pos.col);
			int rowDif=abs(newPos.row-pos.row);

			if(colDif+rowDif==3)
				{
				if((*pChessboard)[newPos.row][newPos.col])
					return capture(newPos);
				else
					return piece::move(newPos);
				}
			else
				return false;
			}

		void getPositions(deque<position> &dp) const
			{
			int i;
			position lPositions[8];
			lPositions[0]=position(pos.row+2,pos.col+1);
			lPositions[1]=position(pos.row+1,pos.col+2);
			lPositions[2]=position(pos.row-1,pos.col+2);
			lPositions[3]=position(pos.row-2,pos.col+1);
			lPositions[4]=position(pos.row-2,pos.col-1);
			lPositions[5]=position(pos.row-1,pos.col-2);
			lPositions[6]=position(pos.row+1,pos.col-2);
			lPositions[7]=position(pos.row+2,pos.col-1);

			for(i=0; i<8; ++i)
				{
				if(isValidPosition(lPositions[i]))
					{
					if((*pChessboard)[lPositions[i].row][lPositions[i].col])
						{
						if((*pChessboard)[lPositions[i].row][lPositions[i].col]->getColor()!=getColor())
							dp.push_back(lPositions[i]);
						}
					else
						dp.push_back(lPositions[i]);
					}
				}

			}

};

class castle: public piece	{
	public:
		castle(bool color,const position &p, matrix<ipointer<piece> > *pCb): piece(CASTLE,p,5,color? 'C': 'c', color,pCb,piece::hAttack|piece::vAttack)
			{
			}

		piece *clone() const
			{
			return new castle(*this);
			}

		bool move(const position &newPos)
			{
			int colDif=abs(newPos.col-pos.col);
			int rowDif=abs(newPos.row-pos.row);
			if((!colDif && rowDif) || (colDif && !rowDif))
				{
				if(isPieceBetween(newPos))
					return false;

				if((*pChessboard)[newPos.row][newPos.col])
					return capture(newPos);
				else
					return piece::move(newPos);
				}
			else
				return false;
			}

		void getPositions(deque<position> &dp) const
			{
			getvPositions(dp);
			gethPositions(dp);
			}

};

class queen: public piece	{
	public:
		queen(bool color, const position &p, matrix<ipointer<piece> > *pCb): piece(QUEEN,p,9,color? 'Q': 'q', color,pCb,piece::hAttack|piece::vAttack|piece::dAttack)
			{
			}

		piece *clone() const
			{
			return new queen(*this);
			}

		bool move(const position &newPos)
			{
			int colDif=abs(newPos.col-pos.col);
			int rowDif=abs(newPos.row-pos.row);
			if((!colDif && rowDif) || (colDif && !rowDif) || (colDif==rowDif))
				{
				if(isPieceBetween(newPos))
					return false;

				if((*pChessboard)[newPos.row][newPos.col])
					return capture(newPos);
				else
					return piece::move(newPos);
				}
			else
				return false;
			}

		void getPositions(deque<position> &dp) const
			{
			getvPositions(dp);
			gethPositions(dp);
			getdPositions(dp);
			}

};

class king: public piece	{
	public:
		king(bool color, const position &p, matrix<ipointer<piece> > *pCb): piece(KING,p,39,color? 'K': 'k', color,pCb,piece::hAttack|piece::vAttack|piece::dAttack)
			{
			}

		piece *clone() const
			{
			return new king(*this);
			}

		bool move(const position &newPos)
			{
			int colDif=abs(newPos.col-pos.col);
			int rowDif=abs(newPos.row-pos.row);

			if((!colDif && rowDif) || (colDif && !rowDif) || (colDif==rowDif))
				{
				if(colDif<2 && rowDif<2)
					{
					if((*pChessboard)[newPos.row][newPos.col])
						return capture(newPos);
					else
						return piece::move(newPos);
					}
				else
					return false;
				}
			else
				return false;
			}

		bool move1(const position &newPos)
			{
			return piece::move(newPos);
			}

		void getPositions(deque<position> &dp) const
			{
			position kpositions[8];
			kpositions[0]=position(pos.row+1,pos.col-1);
			kpositions[1]=position(pos.row+1,pos.col);
			kpositions[2]=position(pos.row+1,pos.col+1);
			kpositions[3]=position(pos.row,pos.col-1);
			kpositions[4]=position(pos.row,pos.col+1);
			kpositions[5]=position(pos.row-1,pos.col-1);
			kpositions[6]=position(pos.row-1,pos.col);
			kpositions[7]=position(pos.row-1,pos.col+1);

			for(int i=0; i<8; ++i)
				{
				if(isValidPosition(kpositions[i]))
					{
					if((*pChessboard)[kpositions[i].row][kpositions[i].col])
						{
						if((*pChessboard)[kpositions[i].row][kpositions[i].col]->getColor()!=getColor())
							dp.push_back(kpositions[i]);
						}
					else
						dp.push_back(kpositions[i]);
					}
				}
			}

};

class pawn: public piece	{
	public:
		pawn(bool color, const position &p, matrix<ipointer<piece> > *pCb): piece(PAWN,p,1,color? 'P': 'p', color,pCb,piece::dAttack|piece::onlyForward|piece::onlyOneSquare)
			{
			}

		piece *clone() const
			{
			return new pawn(*this);
			}

		bool move(const position &newPos, const movement &lastMovement, const char crown)
			{
			//peón al paso
			if(lastMovement.pPiece)
				{
				pawn *pp1;
				if((pp1=dynamic_cast<pawn *>((piece *)(lastMovement.pPiece))) &&
					(abs(lastMovement.pos2.row-lastMovement.pos1.row)==2) &&
					(newPos.col==lastMovement.pos2.col) &&
					(abs(lastMovement.pos2.row-newPos.row)==1))
					{
					piece::move(newPos);
					if(color)
						(*pChessboard)[newPos.row-1][newPos.col]=ipointer<piece>();//liberado
					else
						(*pChessboard)[newPos.row+1][newPos.col]=ipointer<piece>();//liberado

					return true;
					}
				}

			int colDif=abs(newPos.col-pos.col);
			int rowDif=abs(newPos.row-pos.row);
			bool toCapture(colDif==1 && rowDif==1);
			if(colDif>1 || rowDif>2)
				return false;

			if((color && newPos.row<pos.row) || (!color && newPos.row>pos.row))
				return false;

			if(rowDif==2 && moved)
				return false;
			if(rowDif==2 && colDif==1)
				return false;
			if(toCapture)
				{
				if((*pChessboard)[newPos.row][newPos.col])
					{
					capture(newPos);
					if(newPos.row==0 || newPos.row==pChessboard->rows()-1)
						{
						switch(crown)
							{
							case 'q':
								(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new queen(color,pos,pChessboard));
								break;
							case 'c':
								(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new castle(color,pos,pChessboard));
								break;
							case 'b':
								(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new bishop(color,pos,pChessboard));
								break;
							case 'h':
								(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new knight(color,pos,pChessboard));
								break;
							default:
								(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new queen(color,pos,pChessboard));
							}
						}

					return true;
					}
				else
					return false;
				}
			else
				{
				if(isPieceBetween(newPos) || (*pChessboard)[newPos.row][newPos.col])
					return false;

				piece::move(newPos);
				if(newPos.row==0 || newPos.row==pChessboard->rows()-1)
					{
					switch(crown)
						{
						case 'q':
							(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new queen(color,pos,pChessboard));
							break;
						case 'c':
							(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new castle(color,pos,pChessboard));
							break;
						case 'b':
							(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new bishop(color,pos,pChessboard));
							break;
						case 'h':
							(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new knight(color,pos,pChessboard));
							break;
						default:
							(*pChessboard)[pos.row][pos.col]=ipointer<piece>(new queen(color,pos,pChessboard));
						}
					}

				return true;
				}

			}

		void getPositions(deque<position> &dp, const movement &lastMovement) const
			{
			if(getColor())
				{
				if(!moved && !(*pChessboard)[pos.row+2][pos.col] && !(*pChessboard)[pos.row+1][pos.col])
					dp.push_back(position(pos.row+2,pos.col));
				if(isValidPosition(position(pos.row+1,pos.col)) && !(*pChessboard)[pos.row+1][pos.col])
					dp.push_back(position(pos.row+1,pos.col));
				if(isValidPosition(position(pos.row+1,pos.col-1)) && (*pChessboard)[pos.row+1][pos.col-1] && (*pChessboard)[pos.row+1][pos.col-1]->getColor()!=getColor())
					dp.push_back(position(pos.row+1,pos.col-1));
				if(isValidPosition(position(pos.row+1,pos.col+1)) && (*pChessboard)[pos.row+1][pos.col+1] && (*pChessboard)[pos.row+1][pos.col+1]->getColor()!=getColor())
					dp.push_back(position(pos.row+1,pos.col+1));
				}
			else
				{
				if(!moved && !(*pChessboard)[pos.row-2][pos.col] && !(*pChessboard)[pos.row-1][pos.col])
					dp.push_back(position(pos.row-2,pos.col));
				if(isValidPosition(position(pos.row-1,pos.col)) && !(*pChessboard)[pos.row-1][pos.col])
					dp.push_back(position(pos.row-1,pos.col));
				if(isValidPosition(position(pos.row-1,pos.col-1)) && (*pChessboard)[pos.row-1][pos.col-1] && (*pChessboard)[pos.row-1][pos.col-1]->getColor()!=getColor())
					dp.push_back(position(pos.row-1,pos.col-1));
				if(isValidPosition(position(pos.row-1,pos.col+1)) && (*pChessboard)[pos.row-1][pos.col+1] && (*pChessboard)[pos.row-1][pos.col+1]->getColor()!=getColor())
					dp.push_back(position(pos.row-1,pos.col+1));
				}
			//agregando la posicion de peon al paso
			if(lastMovement.pPiece)
				{
				pawn *pp1;
				if((pp1=dynamic_cast<pawn *>((piece *)(lastMovement.pPiece))) &&
					(abs(lastMovement.pos2.row-lastMovement.pos1.row)==2) &&
					(abs(pos.col-lastMovement.pos2.col)==1) &&
					(lastMovement.pos2.row==pos.row))
					{
					dp.push_back(position((color)? pos.row+1: pos.row-1,(pos.col>lastMovement.pos2.col)? pos.col-1: pos.col+1));
					}
				}

			}

};

class round	{
matrix<ipointer<piece> > chessboard;
bool go;//el que está en turno para mover
string player1;
string player2;
int playerId1;
int playerId2;
movement lastMovement;
deque<movement> movements;
int winner;//0 empate; -1 negras; 1 blancas
bool finished;
bool proposedTie;
mutable string message;
int messageFor;

static int playerId;
static REEvaluator REEround;

		round(const round &r): chessboard(r.chessboard), go(r.go), player1(r.player1), player2(r.player2),
		playerId1(r.playerId1), playerId2(r.playerId2), lastMovement(r.lastMovement), movements(r.movements),
		winner(r.winner), finished(r.finished), proposedTie(r.proposedTie), message(r.message), messageFor(r.messageFor)
			{
			int i,j;
			for(i=0; i<chessboard.rows(); ++i)
				for(j=0; j<chessboard.columns(); ++j)
					if(chessboard[i][j])
						chessboard[i][j]->setChessboard(&chessboard);

			}

	public:
		round(): chessboard(8,8), go(true), player1(), player2(),
		playerId1(0), playerId2(0), winner(0), finished(false), proposedTie(false),
		message(), messageFor(0)
			{
			int j;
			for(int i=0; i<chessboard.rows(); ++i)
				for(j=0; j<chessboard.columns(); ++j)
					chessboard[i][j]=0;

			//posiciones iniciales de blancas
			chessboard[0][0]=new castle(true,position(0,0),&chessboard);
			chessboard[0][1]=new knight(true,position(0,1),&chessboard);
			chessboard[0][2]=new bishop(true,position(0,2),&chessboard);
			chessboard[0][3]=new queen(true,position(0,3),&chessboard);
			chessboard[0][4]=new king(true,position(0,4),&chessboard);
			chessboard[0][5]=new bishop(true,position(0,5),&chessboard);
			chessboard[0][6]=new knight(true,position(0,6),&chessboard);
			chessboard[0][7]=new castle(true,position(0,7),&chessboard);

			for(j=0; j<chessboard.columns(); ++j)
				chessboard[1][j]=new pawn(true,position(1,j),&chessboard);

			//posiciones iniciales de negras
			chessboard[7][0]=new castle(false,position(7,0),&chessboard);
			chessboard[7][1]=new knight(false,position(7,1),&chessboard);
			chessboard[7][2]=new bishop(false,position(7,2),&chessboard);
			chessboard[7][3]=new queen(false,position(7,3),&chessboard);
			chessboard[7][4]=new king(false,position(7,4),&chessboard);
			chessboard[7][5]=new bishop(false,position(7,5),&chessboard);
			chessboard[7][6]=new knight(false,position(7,6),&chessboard);
			chessboard[7][7]=new castle(false,position(7,7),&chessboard);

			for(j=0; j<chessboard.columns(); ++j)
				chessboard[6][j]=new pawn(false,position(6,j),&chessboard);
			}

	bool hasMessage(int pId) const
		{
		return (messageFor==pId && message.size());
		}

	string getMessage(int pId) const
		{
		string temp;
		if(pId==messageFor)
			{
			temp=message;
			message.clear();
			}

		return temp;
		}

	//si color es true, corresponde blancas, si es false, corresponde negras, id válido: >0
	int canPlay(bool &color,const string &s)
		{
		if(playerId1>0 && playerId2>0)
			{
			return 0;
			}
		else if(playerId1==0)
			{
			playerId1=++playerId;
			player1=s;
			color=true;

			return playerId1;
			}
		else if(playerId2==0)
			{
			playerId2=++playerId;
			player2=s;
			color=false;

			return playerId2;
			}
		}

	bool isTie() const
		{
		if(movements.size()<6)
			return false;
		else
			{//a1-b1, a3-b3, b1-a1, b3-a3, a1-b1, a3-b3
			deque<movement>::size_type size=movements.size();
			if((movements[size-1].pos1==movements[size-5].pos1 && movements[size-1].pos2==movements[size-5].pos2) && 
				(movements[size-2].pos1==movements[size-6].pos1 && movements[size-2].pos2==movements[size-6].pos2))
				return true;
			else
				return false;
			}
		}

	bool isValidPosition(const position &pos)
		{
		if(pos.row<0 || pos.row>=chessboard.rows())
			return false;
		if(pos.col<0 || pos.col>=chessboard.columns())
			return false;

		return true;
		}

	king *findKing(bool color)
		{
		king *pk;
		for(int i=0; i<chessboard.rows(); ++i)
			for(int j=0; j<chessboard.columns(); ++j)
				if(chessboard[i][j] && chessboard[i][j]->getColor()==color)
					if(pk=dynamic_cast<king *>((piece *)chessboard[i][j]))
						return pk;
		return 0;
		}

	bool canMove(int pId) const
		{
		int i, j;
		for(i=0; i<chessboard.rows(); ++i)
			for(j=0; j<chessboard.columns(); ++j)
				{
				if(((bool)chessboard[i][j]) && chessboard[i][j]->getColor()==go)
					{
					pawn *pp;
					deque<position> dp;
					//el peon es un caso especial, ya que no captura en la misma
					//forma en que avanza, y puede capturar un peón al paso
					if(pp=dynamic_cast<pawn *>((piece *)chessboard[i][j]))
						pp->getPositions(dp,lastMovement);
					else
						chessboard[i][j]->getPositions(dp);

					for(int k=0; k<dp.size(); ++k)
						{
						round rtemp1(*this);
						string s1(convertToLetters(position(i,j),dp[k]));
						rtemp1.play(pId,s1,true);
						king *pk1;
						if(pk1=rtemp1.findKing(go))
							{
							if(pk1->isAttacked())
								continue;
							else
								goto finMate;
							}
						else
							{
							//lanzar excepcion, deberia encontrarlo
							}
						}
					}
				else
					continue;
				}
		finMate:
			;
		if(i==chessboard.rows() && j==chessboard.columns())
			return false;
		else
			return true;

		}

	bool play(int pId, const string &s, bool noRecursive=false)//"d2-d4"
		{
		//probar la jugada en otro tablero, para ver si es permitida
		if(!noRecursive)
			{
			if(finished)
				{
				messageFor=pId;
				message="Partida terminada\n";
				if(!winner)
					message+="Fue tablas\n";
				else if(winner>0)
					message+="Ganó blancas\n";
				else
					message+="Ganó negras\n";
				return false;
				}

			if(pId==playerId1)
				{
				if(!go)
					{
					messageFor=pId;
					message="No es turno de blancas";
					return false;
					}
				}
			else if(pId==playerId2)
				{
				if(go)
					{
					messageFor=pId;
					message="No es turno de negras";
					return false;
					}
				}
			else
				{
				messageFor=pId;
				message="Identificación de jugador inválida";
				return false;
				}

			if(!(REEround.eval(s)))
				{
				messageFor=pId;
				message="Jugada inválida";
				return false;
				}

			if(proposedTie && !(s[0]=='=' || s[0]=='#'))
				{
				messageFor=pId;
				message="Hay una propuesta de tablas, ¿Acepta (=, sí; #, no)?";
				return false;
				}

//cuando se propone tablas
//si el contrario acepta las tablas debe contestar con otro '=', si no, contestar con un '#'
			if(s[0]=='-')
				{
				proposedTie=true;
				go=!go;
				messageFor=(pId==playerId1? playerId2: playerId1);
				message="Hay una propuesta de tablas, ¿Acepta (=, sí; #, no)?";
				return true;
				}
			else if(s[0]=='/')
				{
				finished=true;
				if(go)
					{
					winner=-1;
					messageFor=(pId==playerId1? playerId2: playerId1);
					message="Blancas abandonan, Negras gana la partida";
					}
				else
					{
					winner=1;
					messageFor=(pId==playerId1? playerId2: playerId1);
					message="Negras abandonan, Blancas gana la partida";
					}
				return true;
				}
			else if(s[0]=='=')
				{
				if(proposedTie)
					{
					finished=true;
					winner=0;
					proposedTie=false;
					messageFor=pId;
					message="La partida terminó: tablas";
					return true;
					}
				else
					{
					messageFor=pId;
					message="Este símbolo es válido sólo cuando hay una propuesta de tablas";
					return false;
					}
				}
			else if(s[0]=='#')
				{
				if(proposedTie)
					{
					proposedTie=false;
					go=!go;
					messageFor=(pId==playerId1? playerId2: playerId1);
					message="Se ha rechazado la propuesta de tablas";
					return true;
					}
				else
					{
					messageFor=pId;
					message="Este símbolo es válido sólo cuando hay una propuesta de tablas";
					return false;
					}
				}

			round rtemp(*this);
			if(!(rtemp.play(pId,s,true)))
				{
				messageFor=rtemp.messageFor;
				message=rtemp.message;
				return false;
				}

			if(rtemp.isTie())
				{
				finished=true;
				winner=0;
				messageFor=pId;
				message="Tablas por repetición de jugadas";
				}

			king *pwk, *pbk;
			if(!rtemp.go)
				{
				if(pwk=rtemp.findKing(true))
					if(pwk->isAttacked())
						{
						messageFor=pId;
						message="Imposible, Rey blanco atacado: "+s;
						return false;
						}
				if(pbk=rtemp.findKing(false))
					{
					if(pbk->isAttacked())
						{
						if(rtemp.canMove(pId))
							{
							messageFor=(pId==playerId1? playerId2: playerId1);
							message="++ Jaque";
							}
						else
							{
							finished=true;
							winner=1;
							messageFor=(pId==playerId1? playerId2: playerId1);
							message="+++ Jaque Mate";
							}
						}
					else
						{
						if(!rtemp.canMove(pId))
							{
							finished=true;
							winner=0;
							messageFor=pId;
							message="Rey negro ahogado, tablas";
							}
						}
					}
				}
			else
				{
				if(pbk=rtemp.findKing(false))
					if(pbk->isAttacked())
						{
						messageFor=pId;
						message="Imposible, Rey negro atacado: "+s;
						return false;
						}
				if(pwk=rtemp.findKing(true))
					{
					if(pwk->isAttacked())
						{
						if(rtemp.canMove(pId))
							{
							messageFor=(pId==playerId1? playerId2: playerId1);
							message="++ Jaque";
							}
						else
							{
							finished=true;
							winner=-1;
							messageFor=(pId==playerId1? playerId2: playerId1);
							message="+++ Jaque Mate";
							}
						}
					else
						{
						if(!rtemp.canMove(pId))
							{
							finished=true;
							winner=0;
							messageFor=pId;
							message="Rey blanco ahogado, tablas";
							}
						}
					}
				}
			}

		if(s[0]=='o')
			{
			king *pk;
			if(go)
				pk=dynamic_cast<king *>((piece *)chessboard[0][4]);
			else
				pk=dynamic_cast<king *>((piece *)chessboard[7][4]);

			if(pk)
				{
				if(pk->getColor()==go)
					{
					if(pk->isAttacked())
						{
						messageFor=pId;
						message="El rey está en Jaque, imposible enrocar";
						return false;
						}
					}
				else
					{
					messageFor=pId;
					message="El rey ha sido movido, imposible enrocar";
					return false;
					}
				}
			else
				{
				messageFor=pId;
				message="El rey ha sido movido, imposible enrocar";
				return false;
				}

			if(s.size()<5)
				{
				if(moveKingCastle1(pId))
					{
					go=!go;
					lastMovement=movement(ipointer<piece>(),position(),position());
					movements.push_back(lastMovement);
					return true;
					}
				else
					return false;
				}
			else
				{
				if(moveKingCastle2(pId))
					{
					go=!go;
					lastMovement=movement(ipointer<piece>(),position(),position());
					movements.push_back(lastMovement);
					return true;
					}
				else
					return false;
				}
			}
		else
			{
			int row1, col1, row2, col2;
			row1=convertRow(s[1]);
			col1=convertColumn(s[0]);
			row2=convertRow(s[4]);
			col2=convertColumn(s[3]);

			if(isValidPosition(position(row1,col1)) && isValidPosition(position(row2,col2)))
				{
				if(row1==row2 && col1==col2)
					{
					messageFor=pId;
					message="Es la misma posición";
					return false;
					}

				if(chessboard[row1][col1] && (chessboard[row1][col1]->getColor()==go))//si es una pieza
					{
					if(chessboard[row2][col2])//si en la posicion hay otra pieza
						{//del mismo color
						if(chessboard[row1][col1]->getColor()==chessboard[row2][col2]->getColor())
							{
							messageFor=pId;
							message="Hay otra pieza del mismo color";
							return false;
							}
						}

					pawn *pp;//peón al paso
					if(pp=dynamic_cast<pawn *>((piece *)chessboard[row1][col1]))
						{
						char crown='q';
						if(6<s.size())
							crown=s[s.size()-1];
							
						if(!(pp->move(position(row2,col2),lastMovement,crown)))
							{
							messageFor=pId;
							message="Jugada inválida";
							return false;
							}
						else
							{
							go=!go;
							lastMovement=movement(chessboard[row2][col2],position(row1,col1),position(row2,col2));
							movements.push_back(lastMovement);

							return true;
							}
						}
					else
						{
						if(!(chessboard[row1][col1]->move(position(row2,col2))))
							{
							messageFor=pId;
							message="Jugada inválida";
							return false;
							}
						else
							{
							go=!go;
							lastMovement=movement(chessboard[row2][col2],position(row1,col1),position(row2,col2));
							movements.push_back(lastMovement);

							return true;
							}
						}
					}
				else
					{
					messageFor=pId;
					message="No hay una pieza en la posición o es del contrincante";
					return false;//no es una pieza o no es una pieza de las que corresponden al jugador
					}
				}
			else
				{
				messageFor=pId;
				message="Una de las posiciones es inválida";
				return false;
				}

			}
		}
	
	bool moveKingCastle1(int pId)
		{
		if(go)
			{
			if(chessboard[0][4] && chessboard[0][7])
				{
				if(chessboard[0][4]->moved || chessboard[0][7]->moved)
					{
					messageFor=pId;
					message="Ha movido o el rey o la torre";
					return false;
					}
				else
					{
					if(chessboard[0][4]->isPieceBetween(position(0,7)))
						{
						messageFor=pId;
						message="Hay una pieza entre el rey y la torre";
						return false;
						}
					else
						{
						king *pk;
						chessboard[0][7]->move(position(0,5));
						if(pk=dynamic_cast<king *>((piece *)chessboard[0][4]))
							return pk->move1(position(0,6));
						else
							{
							messageFor=pId;
							message="Error grave, infórmelo al autor";
							return false;
							}

						//chessboard[0][4]->move1(position(0,6));
						}
					}
				}
			else
				{
				messageFor=pId;
				message="Una de las piezas ha sido movida";
				return false;
				}
			}
		else
			{
			if(chessboard[7][4] && chessboard[7][7])
				{
				if(chessboard[7][4]->moved || chessboard[7][7]->moved)
					{
					messageFor=pId;
					message="Ha movido o el rey o la torre";
					return false;
					}
				else
					{
					if(chessboard[7][4]->isPieceBetween(position(7,7)))
						{
						messageFor=pId;
						message="Hay una pieza entre el rey y la torre";
						return false;
						}
					else
						{
						king *pk;
						chessboard[7][7]->move(position(7,5));
						if(pk=dynamic_cast<king *>((piece *)chessboard[7][4]))
							return pk->move1(position(7,6));
						else
							{
							messageFor=pId;
							message="Error grave, infórmelo al autor";
							return false;
							}

						//chessboard[7][4]->move1(position(7,6));
						}
					}
				}
			else
				{
				messageFor=pId;
				message="Una de las piezas ha sido movida";
				return false;
				}
			}
		}

	bool moveKingCastle2(int pId)
		{
		if(go)
			{
			if(chessboard[0][4] && chessboard[0][0])
				{
				if(chessboard[0][4]->moved || chessboard[0][0]->moved)
					{
					messageFor=pId;
					message="Ha movido o el rey o la torre";
					return false;
					}
				else
					{
					if(chessboard[0][4]->isPieceBetween(position(0,0)))
						{
						messageFor=pId;
						message="Hay una pieza entre el rey y la torre";
						return false;
						}
					else
						{
						king *pk;
						chessboard[0][0]->move(position(0,3));
						if(pk=dynamic_cast<king *>((piece *)chessboard[0][4]))
							return pk->move1(position(0,2));
						else
							{
							messageFor=pId;
							message="Error grave, infórmelo al autor";
							return false;
							}

						//chessboard[0][4]->move1(position(0,2));
						}
					}
				}
			else
				{
				messageFor=pId;
				message="Una de las piezas ha sido movida";
				return false;
				}
			}
		else
			{
			if(chessboard[7][4] && chessboard[7][0])
				{
				if(chessboard[7][4]->moved || chessboard[7][0]->moved)
					{
					messageFor=pId;
					message="Ha movido o el rey o la torre";
					return false;
					}
				else
					{
					if(chessboard[7][4]->isPieceBetween(position(7,0)))
						{
						messageFor=pId;
						message="Hay una pieza entre el rey y la torre";
						return false;
						}
					else
						{
						king *pk;
						chessboard[7][0]->move(position(7,3));
						if(pk=dynamic_cast<king *>((piece *)chessboard[7][4]))
							return pk->move1(position(7,2));
						else
							{
							messageFor=pId;
							message="Error grave, infórmelo al autor";
							return false;
							}

						//chessboard[7][4]->move1(position(7,2));
						}
					}
				}
			else
				{
				messageFor=pId;
				message="Una de las piezas ha sido movida";
				return false;
				}
			}
		}

	int convertColumn(char c) const
		{
		switch(c)
			{
			case 'a': return 0;
			case 'b': return 1;
			case 'c': return 2;
			case 'd': return 3;
			case 'e': return 4;
			case 'f': return 5;
			case 'g': return 6;
			case 'h': return 7;
			default: return -1;
			}
		}

	int convertRow(char c) const
		{
		switch(c)
			{
			case '1': return 0;
			case '2': return 1;
			case '3': return 2;
			case '4': return 3;
			case '5': return 4;
			case '6': return 5;
			case '7': return 6;
			case '8': return 7;
			default: return -1;
			}
		}

	char convertColumnToLetter(int n) const
		{
		switch(n)
			{
			case 0: return 'a';
			case 1: return 'b';
			case 2: return 'c';
			case 3: return 'd';
			case 4: return 'e';
			case 5: return 'f';
			case 6: return 'g';
			case 7: return 'h';
			default: return '\0';
			}
		}

	char convertRowToLetter(int n) const
		{
		switch(n)
			{
			case 0: return '1';
			case 1: return '2';
			case 2: return '3';
			case 3: return '4';
			case 4: return '5';
			case 5: return '6';
			case 6: return '7';
			case 7: return '8';
			default: return '\0';
			}
		}

	string convertToLetters(const position &pos1, const position &pos2) const
		{
		string s;
		s.resize(5);
		s[0]=convertColumnToLetter(pos1.col);
		s[1]=convertRowToLetter(pos1.row);
		s[2]='-';
		s[3]=convertColumnToLetter(pos2.col);
		s[4]=convertRowToLetter(pos2.row);
		
		return s;
		}

	friend ostream &operator<<(ostream &os,const round &r)
		{
		os<<std::endl<<r.player2<<" (Black) Vs. "<<r.player1<<" (White)"<<std::endl;
		os<<std::endl<<"\xc2\xc4\xc2\xc4\xc2\xc4\xc2\xc4\xc2\xc4\xc2\xc4\xc2\xc4\xc2\xc4\xc2"<<std::endl;

		for(int i=r.chessboard.rows()-1; i>=0; --i)
			{
			os<<'\xb3';
			for(int j=0; j<r.chessboard.columns(); ++j)
				{
				if(r.chessboard[i][j])
					os<<*(r.chessboard[i][j]);
				else
					os<<' ';
				os<<'\xb3';
				}
			os<<' '<<(i+1)<<std::endl;
			if(i>0)
				os<<"\xc5\xc4\xc5\xc4\xc5\xc4\xc5\xc4\xc5\xc4\xc5\xc4\xc5\xc4\xc5\xc4\xc5"<<std::endl;
			}
		os<<"\xc1\xc4\xc1\xc4\xc1\xc4\xc1\xc4\xc1\xc4\xc1\xc4\xc1\xc4\xc1\xc4\xc1"<<std::endl;
		os<<std::endl;
		os<<" a b c d e f g h"<<std::endl;

		return os;
		}
/*
	friend ostream &operator<<(ostream &os,const round &r)
		{
		os<<endl<<"--------"<<endl;
		os<<r.player2<<endl<<endl;
		for(int i=r.chessboard.rows()-1; i>=0; --i)
			{
			for(int j=0; j<r.chessboard.columns(); ++j)
				{
				if(r.chessboard[i][j])
					os<<*(r.chessboard[i][j]);
				else
					os<<' ';
				}
			os<<' '<<(i+1)<<endl;
			}
		os<<endl;
		os<<"abcdefgh"<<endl;
		os<<r.player1<<endl<<"--------"<<endl;

		return os;
		}
*/
};

int round::playerId=0;
REEvaluator round::REEround="\\-|=|#|/|(o<\\-<o)|(o<\\-<o<\\-<o)|(([a-h]<[1-8])<\\-<([a-h]<[1-8])<(=<(b|h|c|q))?)";

}

using namespace amv;

void main()
{
int id1, id2;
bool color1, color2;
string squit("salir"),s1,s2;

round partida;
std::cout<<partida;

if(!(id1=partida.canPlay(color1,"Kasparov")))
	{
	std::cerr<<"Jugador 1 no aceptado\n";
	return;
	}
if(!(id2=partida.canPlay(color2,"Karpov")))
	{
	std::cerr<<"Jugador 2 no aceptado\n";
	return;
	}

for(;;)
	{
	if(partida.hasMessage(id1))
		std::cerr<<partida.getMessage(id1)<<std::endl;
	std::cout<<"White"<<':';
	std::cin>>s1;
	if(s1==squit)
		break;
	while(true)
		{
		if(partida.play(id1,s1))
			{
			if(partida.hasMessage(id1))
				std::cerr<<partida.getMessage(id1)<<std::endl;
			break;
			}
		if(partida.hasMessage(id1))
			std::cerr<<partida.getMessage(id1)<<std::endl;
		std::cout<<"White"<<':';
		std::cin>>s1;
		if(s1==squit)
			goto fin;
		}

	std::cout<<partida;

	if(partida.hasMessage(id2))
		std::cerr<<partida.getMessage(id2)<<std::endl;
	std::cout<<"Black"<<':';
	std::cin>>s2;
	if(s2==squit)
		break;
	while(true)
		{
		if(partida.play(id2,s2))
			{
			if(partida.hasMessage(id2))
				std::cerr<<partida.getMessage(id2)<<std::endl;
			break;
			}
		if(partida.hasMessage(id2))
			std::cerr<<partida.getMessage(id2)<<std::endl;
		std::cout<<"Black"<<':';
		std::cin>>s2;
		if(s2==squit)
			goto fin;
		}

	std::cout<<partida;
	}
fin:;


/*española
partida.play(id1,"e2-e4");
partida.play(id2,"e7-e5");
partida.play(id1,"g1-f3");
partida.play(id2,"b8-c6");
partida.play(id1,"f1-b5");
partida.play(id2,"d7-d6");
partida.play(id1,"c2-c3");
partida.play(id2,"c6-b8");
*/
/*Alekhine
partida.play("e2-e4");
partida.play("g8-f6");
partida.play("e4-e5");
partida.play("f6-d5");
partida.play("c2-c4");
partida.play("d5-b6");
*/

std::cout<<"\n*** Autor: Ariel Medina ***\n";

}