2545 lines
63 KiB
C++
2545 lines
63 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2004, University in Hagen, Department of Computer Science,
|
|
Database Systems for New Applications.
|
|
|
|
SECONDO 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.
|
|
|
|
SECONDO is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with SECONDO; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
----
|
|
|
|
//paragraph [1] title: [{\Large \bf ] [}]
|
|
|
|
August 2007. M. Spiekermann. Some bug fixes for bugs recognized using a 64bit linux
|
|
platform.
|
|
|
|
1) Member mpoint in Class Movingchesspiece wasn't initialized correctly.
|
|
2) Some moves of the pgn file were not recognized which lead to reading
|
|
uninitialized data
|
|
3) After fixing 1-2 creating movingpoints from a match fails. Needs still
|
|
to be fixed !!!
|
|
|
|
|
|
[1] Datatypes for ChessAlgebra (implementation)
|
|
|
|
*/
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#include "chessTypes.h"
|
|
|
|
using namespace datetime;
|
|
using namespace temporalalgebra;
|
|
|
|
namespace ChessAlgebra {
|
|
|
|
|
|
/*
|
|
2 auxiliary functions implementation
|
|
|
|
*/
|
|
|
|
/*
|
|
compares two MetainfoEntry objects using strcmp on key component, which is
|
|
used for sorting metainfos DBArray in class chessgame
|
|
|
|
*/
|
|
int MetainfoEntryCmp( const void *v1, const void *v2 )
|
|
{
|
|
MetainfoEntry * mi1 = ( MetainfoEntry* ) v1;
|
|
MetainfoEntry* mi2 = ( MetainfoEntry* ) v2;
|
|
|
|
return ( strcmp( mi1->key, mi2->key ) );
|
|
}
|
|
|
|
/*
|
|
3 Class implementations
|
|
|
|
3.1 Class Material
|
|
|
|
*/
|
|
Material::Material() {}
|
|
Material::~Material() {}
|
|
|
|
Material::Material( char wPawn, char wKnight, char wRook,
|
|
char wBishop, char wQueen, char wKing,
|
|
char bPawn, char bKnight, char bRook,
|
|
char bBishop, char bQueen, char bKing ):
|
|
IndexableAttribute(true)
|
|
{
|
|
material[ WHITE_PAWN ] = wPawn;
|
|
material[ WHITE_KNIGHT ] = wKnight;
|
|
material[ WHITE_ROOK ] = wRook;
|
|
material[ WHITE_BISHOP ] = wBishop;
|
|
material[ WHITE_QUEEN ] = wQueen;
|
|
material[ WHITE_KING ] = wKing;
|
|
material[ BLACK_PAWN ] = bPawn;
|
|
material[ BLACK_KNIGHT ] = bKnight;
|
|
material[ BLACK_ROOK ] = bRook;
|
|
material[ BLACK_BISHOP ] = bBishop;
|
|
material[ BLACK_QUEEN ] = bQueen;
|
|
material[ BLACK_KING ] = bKing;
|
|
|
|
// calculate white material
|
|
char sum = 0;
|
|
for ( int i = WHITE_PAWN; i <= WHITE_KING; i++ )
|
|
sum += material[ i ];
|
|
material[ WHITE_MATERIAL ] = sum;
|
|
|
|
// calculate black material
|
|
sum = 0;
|
|
for ( int i = BLACK_PAWN; i <= BLACK_KING; i++ )
|
|
sum += material[ i ];
|
|
material[ BLACK_MATERIAL ] = sum;
|
|
}
|
|
|
|
Material::Material( char const *mat ):
|
|
IndexableAttribute(true)
|
|
{
|
|
for ( int i = WHITE_PAWN; i <= BLACK_KING; i++ )
|
|
material[ i ] = mat[ i ];
|
|
SetDefined( true );
|
|
|
|
// calculate white material
|
|
char sum = 0;
|
|
for ( int i = WHITE_PAWN; i <= WHITE_KING; i++ )
|
|
sum += material[ i ];
|
|
material[ WHITE_MATERIAL ] = sum;
|
|
|
|
// calculate black material
|
|
sum = 0;
|
|
for ( int i = BLACK_PAWN; i <= BLACK_KING; i++ )
|
|
sum += material[ i ];
|
|
material[ BLACK_MATERIAL ] = sum;
|
|
}
|
|
|
|
int Material::Compare( const Attribute* arg ) const
|
|
{
|
|
const Material * mat = ( Material* ) arg;
|
|
if ( !IsDefined() && !mat->IsDefined() )
|
|
return 0;
|
|
if ( !IsDefined() && mat->IsDefined() )
|
|
return -1;
|
|
if ( IsDefined() && !mat->IsDefined() )
|
|
return 1;
|
|
|
|
// both objects defined, compare material positions
|
|
int cmp;
|
|
|
|
// compare white pawns
|
|
cmp = material[ WHITE_PAWN ] - mat->material[ WHITE_PAWN ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black pawns
|
|
cmp = material[ BLACK_PAWN ] - mat->material[ BLACK_PAWN ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare white knights
|
|
cmp = material[ WHITE_KNIGHT ] - mat->material[ WHITE_KNIGHT ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black knights
|
|
cmp = material[ BLACK_KNIGHT ] - mat->material[ BLACK_KNIGHT ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare white bishops
|
|
cmp = material[ WHITE_BISHOP ] - mat->material[ WHITE_BISHOP ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black bishops
|
|
cmp = material[ BLACK_BISHOP ] - mat->material[ BLACK_BISHOP ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare white rooks
|
|
cmp = material[ WHITE_ROOK ] - mat->material[ WHITE_ROOK ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black rooks
|
|
cmp = material[ BLACK_ROOK ] - mat->material[ BLACK_ROOK ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare white queens
|
|
cmp = material[ WHITE_QUEEN ] - mat->material[ WHITE_QUEEN ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black queens
|
|
cmp = material[ BLACK_QUEEN ] - mat->material[ BLACK_QUEEN ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// Kings should be always 1, so they are not compared.
|
|
return 0;
|
|
}
|
|
|
|
int Material::ComparePieceValues( const Attribute* arg ) const
|
|
{
|
|
const Material* mat = ( Material* ) arg;
|
|
if ( !IsDefined() && !mat->IsDefined() )
|
|
return 0;
|
|
if ( !IsDefined() && mat->IsDefined() )
|
|
return -1;
|
|
if ( IsDefined() && !mat->IsDefined() )
|
|
return 1;
|
|
|
|
if (PieceValue() < mat->PieceValue())
|
|
return -1;
|
|
|
|
if (PieceValue() > mat->PieceValue())
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool Material::Adjacent( const Attribute *arg ) const
|
|
{
|
|
//TODO ?
|
|
return false;
|
|
}
|
|
|
|
size_t Material::Sizeof() const
|
|
{
|
|
return sizeof( Material );
|
|
}
|
|
|
|
size_t Material::HashValue() const
|
|
{
|
|
|
|
return material[ BLACK_PAWN ] +
|
|
material[ BLACK_KNIGHT ] * 9 +
|
|
material[ BLACK_BISHOP ] * 27 +
|
|
material[ BLACK_ROOK ] * 81 +
|
|
material[ BLACK_QUEEN ] * 243 +
|
|
material[ WHITE_PAWN ] * 729 +
|
|
material[ WHITE_KNIGHT ] * 2187 +
|
|
material[ WHITE_BISHOP ] * 6561 +
|
|
material[ WHITE_ROOK ] * 19683 +
|
|
material[ WHITE_QUEEN ] * 59049;
|
|
|
|
}
|
|
|
|
void Material::CopyFrom( const Attribute* arg )
|
|
{
|
|
const Material* mat2 = (Material*) arg;
|
|
SetDefined( mat2->IsDefined());
|
|
for ( int i=0; i<14; i++ )
|
|
{
|
|
material[ i ] = mat2->material[ i ];
|
|
}
|
|
}
|
|
|
|
Material* Material::Clone() const
|
|
{
|
|
return new Material( *this );
|
|
}
|
|
|
|
void Material::WriteTo( char *dest ) const
|
|
{
|
|
*dest++ = IsDefined() ? '1' : '0';
|
|
for (int i=0; i < 14; i++)
|
|
*dest++ = material[ i ];
|
|
}
|
|
|
|
void Material::ReadFrom( const char *src )
|
|
{
|
|
SetDefined( (*src++ == '1') ? true : false);
|
|
for (int i=0; i < 14; i++)
|
|
material[ i ] = *src++;
|
|
}
|
|
|
|
SmiSize Material::SizeOfChars() const
|
|
{
|
|
return 14;
|
|
}
|
|
|
|
int Material::Count ( string type ) const
|
|
{
|
|
// count all figures
|
|
if ( type == "all" )
|
|
return ( material[ WHITE_MATERIAL ] + material[ BLACK_MATERIAL ] );
|
|
|
|
// count all white figures
|
|
if ( type == "white" )
|
|
return material[ WHITE_MATERIAL ];
|
|
|
|
// count all black figures
|
|
if ( type == "black" )
|
|
return material[ BLACK_MATERIAL ];
|
|
|
|
// search type string and return respective value
|
|
for ( int i = WHITE_PAWN; i <= BLACK_KING; i++ )
|
|
if ( type == DecodeAgent( i ) )
|
|
return material[ i ];
|
|
|
|
set<char> agents;
|
|
map<char, int> str2agent;
|
|
str2agent['P'] = WHITE_PAWN;
|
|
str2agent['N'] = WHITE_KNIGHT;
|
|
str2agent['B'] = WHITE_BISHOP;
|
|
str2agent['R'] = WHITE_ROOK;
|
|
str2agent['Q'] = WHITE_QUEEN;
|
|
str2agent['K'] = WHITE_KING;
|
|
|
|
str2agent['p'] = BLACK_PAWN;
|
|
str2agent['n'] = BLACK_KNIGHT;
|
|
str2agent['b'] = BLACK_BISHOP;
|
|
str2agent['r'] = BLACK_ROOK;
|
|
str2agent['q'] = BLACK_QUEEN;
|
|
str2agent['k'] = BLACK_KING;
|
|
|
|
for ( size_t i = 0; i < type.length(); i++ )
|
|
{
|
|
agents.insert( type[i] );
|
|
}
|
|
|
|
int sum = 0;
|
|
set<char>::iterator it = agents.begin();
|
|
for(; it != agents.end(); it++) {
|
|
map<char,int>::iterator it2 = str2agent.find( *it );
|
|
if ( it2 != str2agent.end() )
|
|
sum += material[ it2->second ];
|
|
}
|
|
return sum;
|
|
|
|
// unknown type string
|
|
return -1;
|
|
}
|
|
|
|
bool Material::IsEqual ( const Material* mat )
|
|
{
|
|
for ( int i = WHITE_PAWN; i <= BLACK_KING; i++ )
|
|
if ( ( material[ i ] != mat->material[ i ] ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int Material::PieceValue() const
|
|
{
|
|
int value = 0;
|
|
for ( int i = WHITE_PAWN; i <= BLACK_KING; i++ )
|
|
{
|
|
value += material[ i ] * PIECE_WEIGHT[ i ];
|
|
}
|
|
return value;
|
|
}
|
|
|
|
|
|
/*
|
|
3.2 Class Move
|
|
|
|
*/
|
|
Move::Move() {}
|
|
Move::~Move() {}
|
|
|
|
Move::Move( int moveNumber,
|
|
string agent, string captured,
|
|
string startFile, char startRow,
|
|
string endFile, char endRow,
|
|
bool check ):
|
|
IndexableAttribute(true)
|
|
{
|
|
char agentID = EncodeAgent( agent );
|
|
char capturedID = EncodeAgent( captured );
|
|
CheckBounds( startFile[ 0 ], startRow );
|
|
CheckBounds( endFile[ 0 ], endRow );
|
|
|
|
this->moveNumber = moveNumber;
|
|
this->agentID = agentID;
|
|
this->capturedID = capturedID;
|
|
this->startFile = startFile[ 0 ];
|
|
this->startRow = startRow;
|
|
this->endFile = endFile[ 0 ];
|
|
this->endRow = endRow;
|
|
this->check = check;
|
|
SetDefined ( true );
|
|
}
|
|
|
|
Move::Move( int moveNumber,
|
|
char agentID, char capturedID,
|
|
char startFile, char startRow,
|
|
char endFile, char endRow,
|
|
bool check ):
|
|
IndexableAttribute(true)
|
|
{
|
|
CheckBounds( startFile, startRow );
|
|
CheckBounds( endFile, endRow );
|
|
|
|
if ( ( agentID < 0 ) || ( agentID > 13 ) )
|
|
agentID = UNDEF;
|
|
|
|
if ( ( capturedID < 0 ) || ( capturedID > 13 ) )
|
|
capturedID = UNDEF;
|
|
|
|
this->moveNumber = moveNumber;
|
|
this->agentID = agentID;
|
|
this->capturedID = capturedID;
|
|
this->startFile = startFile;
|
|
this->startRow = startRow;
|
|
this->endFile = endFile;
|
|
this->endRow = endRow;
|
|
this->check = check;
|
|
SetDefined ( true );
|
|
}
|
|
|
|
/*
|
|
Two moves are equal if they move the same agent from the same
|
|
start field to the same end field.
|
|
|
|
*/
|
|
|
|
int Move::Compare( const Attribute* arg ) const
|
|
{
|
|
const Move * move = ( Move* ) arg;
|
|
if ( !IsDefined() && !move->IsDefined() )
|
|
return 0;
|
|
if ( !IsDefined() && move->IsDefined() )
|
|
return -1;
|
|
if ( IsDefined() && !move->IsDefined() )
|
|
return 1;
|
|
|
|
// both objects defined
|
|
int cmp;
|
|
|
|
// compare startfile
|
|
cmp = startFile - move->startFile;
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare startrow
|
|
cmp = startRow - move->startRow;
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare endfile
|
|
cmp = endFile - move->endFile;
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare endrow
|
|
cmp = endRow - move->endRow;
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare agentID
|
|
cmp = agentID - move->agentID;
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare check state
|
|
/*
|
|
if ( check && !move->check )
|
|
return 1;
|
|
if ( !check && move->check )
|
|
return -1;
|
|
*/
|
|
|
|
return cmp;
|
|
}
|
|
|
|
bool Move::Adjacent( const Attribute *arg ) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
size_t Move::Sizeof() const
|
|
{
|
|
return sizeof( Move );
|
|
}
|
|
|
|
size_t Move::HashValue() const
|
|
{
|
|
if (IsDefined()) {
|
|
return moveNumber + check +
|
|
agentID + capturedID +
|
|
startFile + startRow +
|
|
endFile + endRow;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void Move::CopyFrom( const Attribute* arg )
|
|
{
|
|
const Move* move2 = (Move*) arg;
|
|
SetDefined(move2->IsDefined());
|
|
moveNumber = move2->moveNumber;
|
|
agentID = move2->agentID;
|
|
capturedID = move2->capturedID;
|
|
startFile = move2->startFile;
|
|
startRow = move2->startRow;
|
|
endFile = move2->endFile;
|
|
endRow = move2->endRow;
|
|
check = move2->check;
|
|
}
|
|
|
|
Move* Move::Clone() const
|
|
{
|
|
return new Move( *this );
|
|
}
|
|
|
|
void Move::WriteTo( char *dest ) const
|
|
{
|
|
*dest++ = IsDefined() ? '1' : '0';
|
|
*dest++ = startFile;
|
|
*dest++ = startRow;
|
|
*dest++ = endFile;
|
|
*dest++ = endRow;
|
|
*dest++ = agentID;
|
|
*dest++ = check ? '1' : '0';
|
|
*dest++ = capturedID;
|
|
|
|
ostringstream tmp;
|
|
tmp << moveNumber;
|
|
strcpy(dest, tmp.str().c_str() );
|
|
}
|
|
|
|
void Move::ReadFrom( const char *src )
|
|
{
|
|
SetDefined((*src++ == '1') ? true : false);
|
|
startFile = *src++;
|
|
startRow = *src++;
|
|
endFile = *src++;
|
|
endRow = *src++;
|
|
agentID = *src++;
|
|
check = (*src++ == '1') ? true : false;
|
|
capturedID = *src++;
|
|
|
|
istringstream tmp(src);
|
|
tmp >> moveNumber;
|
|
}
|
|
|
|
SmiSize Move::SizeOfChars() const
|
|
{
|
|
return ( 8 + sizeof(int) );
|
|
}
|
|
|
|
/*
|
|
3.2 Class Position
|
|
|
|
*/
|
|
Position::Position() {}
|
|
Position::~Position() {}
|
|
|
|
Position::Position( int moveNumber ):
|
|
IndexableAttribute(true)
|
|
{
|
|
this->moveNumber = moveNumber;
|
|
for ( int i = 0; i < 64; i++ )
|
|
gamefield[ i ] = NONE;
|
|
|
|
for ( int i = WHITE_PAWN; i <= BLACK_KING; i++ )
|
|
material[ i ] = 0;
|
|
|
|
SetDefined(true);
|
|
}
|
|
|
|
/*
|
|
Two positions are equal, if they have the same pieces at
|
|
the same fields.
|
|
|
|
First the pieces (material) are compared.
|
|
|
|
Afterwards all 64 fields are compared. If some field of
|
|
the local position p1 has a piece but the argument's position p2
|
|
does not have a piece on that field then p1 < p2 yields.
|
|
|
|
*/
|
|
|
|
int Position::Compare( const Attribute* arg ) const
|
|
{
|
|
const Position* pos = ( Position* ) arg;
|
|
if ( !IsDefined() && !pos->IsDefined() )
|
|
return 0;
|
|
if ( !IsDefined() && pos->IsDefined() )
|
|
return -1;
|
|
if ( IsDefined() && !pos->IsDefined() )
|
|
return 1;
|
|
|
|
// both objects defined, compare material positions
|
|
int cmp;
|
|
|
|
// compare white pawns
|
|
cmp = material[ WHITE_PAWN ] - pos->material[ WHITE_PAWN ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black pawns
|
|
cmp = material[ BLACK_PAWN ] - pos->material[ BLACK_PAWN ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare white knights
|
|
cmp = material[ WHITE_KNIGHT ] - pos->material[ WHITE_KNIGHT ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black knights
|
|
cmp = material[ BLACK_KNIGHT ] - pos->material[ BLACK_KNIGHT ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare white bishops
|
|
cmp = material[ WHITE_BISHOP ] - pos->material[ WHITE_BISHOP ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black bishops
|
|
cmp = material[ BLACK_BISHOP ] - pos->material[ BLACK_BISHOP ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare white rooks
|
|
cmp = material[ WHITE_ROOK ] - pos->material[ WHITE_ROOK ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black rooks
|
|
cmp = material[ BLACK_ROOK ] - pos->material[ BLACK_ROOK ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare white queens
|
|
cmp = material[ WHITE_QUEEN ] - pos->material[ WHITE_QUEEN ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare black queens
|
|
cmp = material[ BLACK_QUEEN ] - pos->material[ BLACK_QUEEN ];
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// material is equal in both positions, compare gamefield positions
|
|
for ( int i = 0; i < 64; i++ )
|
|
{
|
|
if ((gamefield[ i ] != NONE) && (pos->gamefield[ i ] == NONE))
|
|
return 1;
|
|
if ((gamefield[ i ] == NONE) && (pos->gamefield[ i ] != NONE))
|
|
return -1;
|
|
|
|
cmp = (gamefield[ i ] - pos->gamefield[ i ]);
|
|
if (cmp != 0)
|
|
return cmp;
|
|
}
|
|
return cmp;
|
|
}
|
|
|
|
|
|
int Position::ComparePieceValues( const Attribute* arg ) const
|
|
{
|
|
const Position* pos = ( Position* ) arg;
|
|
if ( !IsDefined() && !pos->IsDefined() )
|
|
return 0;
|
|
if ( !IsDefined() && pos->IsDefined() )
|
|
return -1;
|
|
if ( IsDefined() && !pos->IsDefined() )
|
|
return 1;
|
|
|
|
Material localMat ;
|
|
GetMaterial(&localMat);
|
|
Material argMat;
|
|
pos->GetMaterial(&argMat);
|
|
|
|
if (localMat.PieceValue() < argMat.PieceValue())
|
|
return -1;
|
|
|
|
if (localMat.PieceValue() > argMat.PieceValue())
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
bool Position::Adjacent( const Attribute *arg ) const
|
|
{
|
|
//TODO ?
|
|
return false;
|
|
}
|
|
|
|
size_t Position::Sizeof() const
|
|
{
|
|
return sizeof( Position );
|
|
}
|
|
|
|
size_t Position::HashValue() const
|
|
{
|
|
size_t retval = 0;
|
|
if (IsDefined()) {
|
|
for(int i = 0; i < 64; i++){
|
|
retval += gamefield[ i ];
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void Position::CopyFrom( const Attribute* arg )
|
|
{
|
|
const Position* pos2 = (Position*) arg;
|
|
SetDefined(pos2->IsDefined());
|
|
moveNumber = pos2->moveNumber;
|
|
for ( int i=0; i<12; i++ )
|
|
{
|
|
material[ i ] = pos2->material[ i ];
|
|
}
|
|
for ( int i=0; i<64; i++ )
|
|
{
|
|
gamefield[ i ] = pos2->gamefield[ i ];
|
|
}
|
|
}
|
|
|
|
Position* Position::Clone() const
|
|
{
|
|
return new Position ( *this );
|
|
}
|
|
|
|
void Position::WriteTo( char *dest ) const
|
|
{
|
|
*dest++ = IsDefined() ? '1' : '0';
|
|
|
|
for (int i=0; i < 64; i++)
|
|
*dest++ = gamefield[ i ];
|
|
|
|
for (int i=0; i < 12; i++)
|
|
*dest++ = material[ i ];
|
|
|
|
ostringstream tmp;
|
|
tmp << moveNumber;
|
|
strcpy(dest, tmp.str().c_str() );
|
|
}
|
|
|
|
void Position::ReadFrom( const char *src )
|
|
{
|
|
SetDefined((*src++ == '1') ? true : false);
|
|
|
|
for (int i=0; i < 64; i++)
|
|
gamefield[ i ] = *src++;
|
|
|
|
for (int i=0; i < 12; i++)
|
|
material[ i ] = *src++;
|
|
|
|
istringstream tmp(src);
|
|
tmp >> moveNumber;
|
|
}
|
|
|
|
SmiSize Position::SizeOfChars() const
|
|
{
|
|
return ( 77 + sizeof(int) );
|
|
}
|
|
|
|
ostream& Position::Print( ostream& os ) const
|
|
{
|
|
return ( os << *this );
|
|
}
|
|
|
|
ostream& operator <<( ostream& os, const Position& pos )
|
|
{
|
|
os << "Move number : " << pos.moveNumber << endl;
|
|
for ( int i = 7; i >= 0; i-- )
|
|
{
|
|
for ( int j = 0; j < 8; j++ )
|
|
{
|
|
os << ( DecodeAgent( pos.gamefield[ ( i * 8 ) + j ] ) ) << " ";
|
|
}
|
|
os << endl;
|
|
}
|
|
os << endl << endl;
|
|
return os;
|
|
}
|
|
|
|
void Position::Reset()
|
|
{
|
|
for ( int i = 0; i < 64; i++ )
|
|
gamefield[ i ] = NONE;
|
|
|
|
for ( int i = 0; i < 12; i++ )
|
|
material[ i ] = 0;
|
|
}
|
|
|
|
void Position::StartPos()
|
|
{
|
|
// set empty positions
|
|
for ( int i = 16; i < 48; i++ )
|
|
gamefield[ i ] = NONE;
|
|
|
|
// set white and black pawns
|
|
for ( int i = 0; i < 8; i++ )
|
|
{
|
|
gamefield[ 8 + i ] = WHITE_PAWN;
|
|
gamefield[ 48 + i ] = BLACK_PAWN;
|
|
}
|
|
|
|
// set white rooks, knights, bishop, king and queen
|
|
gamefield[ 0 ] = WHITE_ROOK;
|
|
gamefield[ 1 ] = WHITE_KNIGHT;
|
|
gamefield[ 2 ] = WHITE_BISHOP;
|
|
gamefield[ 3 ] = WHITE_QUEEN;
|
|
gamefield[ 4 ] = WHITE_KING;
|
|
gamefield[ 5 ] = WHITE_BISHOP;
|
|
gamefield[ 6 ] = WHITE_KNIGHT;
|
|
gamefield[ 7 ] = WHITE_ROOK;
|
|
|
|
// set black rooks, knights, bishop, king and queen
|
|
gamefield[ 56 ] = BLACK_ROOK;
|
|
gamefield[ 57 ] = BLACK_KNIGHT;
|
|
gamefield[ 58 ] = BLACK_BISHOP;
|
|
gamefield[ 59 ] = BLACK_QUEEN;
|
|
gamefield[ 60 ] = BLACK_KING;
|
|
gamefield[ 61 ] = BLACK_BISHOP;
|
|
gamefield[ 62 ] = BLACK_KNIGHT;
|
|
gamefield[ 63 ] = BLACK_ROOK;
|
|
|
|
// set white material
|
|
material[ WHITE_PAWN ] = 8;
|
|
material[ WHITE_KNIGHT ] = 2;
|
|
material[ WHITE_BISHOP ] = 2;
|
|
material[ WHITE_ROOK ] = 2;
|
|
material[ WHITE_QUEEN ] = 1;
|
|
material[ WHITE_KING ] = 1;
|
|
|
|
// set black material
|
|
material[ BLACK_PAWN ] = 8;
|
|
material[ BLACK_KNIGHT ] = 2;
|
|
material[ BLACK_BISHOP ] = 2;
|
|
material[ BLACK_ROOK ] = 2;
|
|
material[ BLACK_QUEEN ] = 1;
|
|
material[ BLACK_KING ] = 1;
|
|
}
|
|
|
|
int Position::AddAgent( string agentStr, char file, char row )
|
|
{
|
|
// encode agent position (file and row will be bound to allowed values)
|
|
char pos = EncodePosition( file, row );
|
|
|
|
// get agentID on agent position
|
|
char oldAgentID = ( gamefield[ ( int ) pos ] );
|
|
|
|
// check, if agent position is empty and return errorcode -1 otherwhise
|
|
if ( oldAgentID == NONE )
|
|
{
|
|
// store agent, if agentStr is valid or return errorcode -2 otherwhise
|
|
char agentID = ( ( EncodeAgent( agentStr ) ) );
|
|
if ( ( agentID != NONE ) || ( agentID != UNDEF ) )
|
|
{
|
|
gamefield[ ( int ) pos ] = EncodeAgent( agentStr );
|
|
material[ ( int ) EncodeAgent( agentStr ) ] ++;
|
|
SetDefined(true);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
SetDefined(false);
|
|
return -2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetDefined(false);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
string Position::GetAgent( char file, char row, bool shortname )
|
|
{
|
|
char pos = EncodePosition( file, row );
|
|
if ( !shortname )
|
|
{
|
|
return DecodeAgent( ( int ) gamefield[ ( int ) pos ] );
|
|
}
|
|
else
|
|
{
|
|
return DecodeAgentShort( ( int ) gamefield[ ( int ) pos ] );
|
|
}
|
|
}
|
|
|
|
string Position::GetAgentShort( char file, char row )
|
|
{
|
|
return GetAgent( file, row, true );
|
|
}
|
|
|
|
void Position::GetMaterial( Material* result ) const
|
|
{
|
|
for ( int i = WHITE_PAWN; i <= BLACK_KING; i++ )
|
|
{
|
|
result->material[ i ] = material[ i ];
|
|
}
|
|
|
|
// calculate Count("White")
|
|
char sum = 0;
|
|
for ( int i = WHITE_PAWN; i <= WHITE_KING; i++ )
|
|
sum += material[ i ];
|
|
result->material[ WHITE_MATERIAL ] = sum;
|
|
|
|
// calculate Count("Black")
|
|
sum = 0;
|
|
for ( int i = BLACK_PAWN; i <= BLACK_KING; i++ )
|
|
sum += material[ i ];
|
|
result->material[ BLACK_MATERIAL ] = sum;
|
|
|
|
// test of Material::WriteTo() and Material::ReadTo()
|
|
/*
|
|
char matStr[result->SizeOfChars()];
|
|
result->WriteTo(&matStr[0]);
|
|
for ( int i = 0; i < 14; i++ )
|
|
{
|
|
result->material[ i ] = 0;
|
|
}
|
|
result->defined = ( false );
|
|
result->ReadFrom(&matStr[0]);
|
|
*/
|
|
}
|
|
|
|
bool Position::TestField ( string agentStr, char file, int row )
|
|
{
|
|
char agentPosID = gamefield[ ( int ) EncodePosition( file, row ) ];
|
|
char agentID = EncodeAgent( agentStr );
|
|
|
|
if ( agentID == agentPosID )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void Position::ShowBoard(ostream& os) {
|
|
|
|
os << endl;
|
|
for (int row=8; row > 0; row--) {
|
|
os << row;
|
|
for (char file='a'; file <= 'h'; file++) {
|
|
char agent = gamefield[ ( int ) EncodePosition( file, row ) ];
|
|
os << ' ' << DecodeAgentShort(agent);
|
|
}
|
|
os << endl;
|
|
}
|
|
os << " a b c d e f g h" << endl;
|
|
}
|
|
|
|
|
|
void Position::Range( Position* result, char startfile, char startrow,
|
|
char endfile, char endrow )
|
|
{
|
|
// check gamefields and set them to allowed values, if they are out of bound
|
|
CheckBounds( startfile, startrow );
|
|
CheckBounds( endfile, endrow );
|
|
result->Reset();
|
|
|
|
for ( int row = startrow; row <= endrow; row++ )
|
|
{
|
|
for ( char file = startfile; file <= endfile; file++ )
|
|
{
|
|
int pos = (int) EncodePosition( file, row );
|
|
char agentId = gamefield[ pos ];
|
|
result->gamefield[ pos ] = agentId;
|
|
result->material[ ( int ) agentId ]++;
|
|
}
|
|
}
|
|
|
|
result->moveNumber = moveNumber;
|
|
result->SetDefined( true );
|
|
}
|
|
|
|
bool Position::IsIncluded( Position * pos )
|
|
{
|
|
for ( int i = 0; i < 64; i++ )
|
|
if ( ( gamefield[ i ] != NONE ) &&
|
|
( gamefield[ i ] != pos->gamefield[ i ] ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
/*
|
|
3.4 Class Chessgame
|
|
|
|
*/
|
|
Chessgame::Chessgame() {}
|
|
Chessgame::~Chessgame() {}
|
|
|
|
Chessgame::Chessgame( int metainfoCnt, int movesCnt ) :
|
|
IndexableAttribute(true),
|
|
metainfo( metainfoCnt ), moves( movesCnt ), positions( 0 )
|
|
{
|
|
White[ 0 ] = '\0';
|
|
Black[ 0 ] = '\0';
|
|
WhiteElo[ 0 ] = '\0';
|
|
BlackElo[ 0 ] = '\0';
|
|
Event[ 0 ] = '\0';
|
|
Site[ 0 ] = '\0';
|
|
Date[ 0 ] = '\0';
|
|
ECO[ 0 ] = '\0';
|
|
Result[ 0 ] = '\0';
|
|
}
|
|
|
|
int Chessgame::Compare( const Attribute* arg ) const
|
|
{
|
|
const Chessgame * game= ( Chessgame* ) arg;
|
|
if ( !IsDefined() && !game->IsDefined() )
|
|
return 0;
|
|
if ( !IsDefined()&& game->IsDefined())
|
|
return -1;
|
|
if ( IsDefined()&& !game->IsDefined() )
|
|
return 1;
|
|
|
|
// both objects defined, compare metainfos
|
|
int cmp;
|
|
|
|
// compare Date
|
|
cmp = strcmp( Date, game->Date );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare Event
|
|
cmp = strcmp( Event, game->Event );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare White
|
|
cmp = strcmp( White, game->White );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare Black
|
|
cmp = strcmp( Black, game->Black );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare ECO
|
|
cmp = strcmp( ECO, game->ECO );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare result
|
|
cmp = strcmp( Result, game->Result );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare Site
|
|
cmp = strcmp( Site, game->Site );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare WhiteElo
|
|
cmp = strcmp( WhiteElo, game->WhiteElo );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare BlackElo
|
|
cmp = strcmp( BlackElo, game->BlackElo );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
cmp = ( metainfo.Size() - game->metainfo.Size() );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// both metainfo DBArrays are of the same size and because they are sorted,
|
|
// equal entrys must be on the same position
|
|
for (int i = 0; i < metainfo.Size(); i++)
|
|
{
|
|
MetainfoEntry m1 = GetMetainfoEntry( i );
|
|
MetainfoEntry m2 = game->GetMetainfoEntry( i );
|
|
|
|
// compare key
|
|
cmp = strcmp( m1.key, m2.key );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare value
|
|
cmp = strcmp( m1.value, m2.value );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
}
|
|
|
|
// all metainfos are eqaul at this point
|
|
// compare move count
|
|
cmp = ( moves.Size() - game->moves.Size() );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
for (int i = 0; i < moves.Size(); i++)
|
|
{
|
|
MoveData m1 = GetMoveData( i );
|
|
MoveData m2 = GetMoveData( i );
|
|
|
|
// compare start-position
|
|
cmp = ( m1.GetStartPos() - m2.GetStartPos() );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare end-position
|
|
cmp = ( m1.GetEndPos() - m2.GetEndPos() );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
|
|
// compare new agent
|
|
cmp = ( m1.GetNewAgentID() - m2.GetNewAgentID() );
|
|
if (cmp != 0)
|
|
return cmp;
|
|
}
|
|
|
|
// both games are equal
|
|
return ( 0 );
|
|
}
|
|
|
|
bool Chessgame::Adjacent( const Attribute *arg ) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
size_t Chessgame::Sizeof() const
|
|
{
|
|
return sizeof( Chessgame );
|
|
}
|
|
|
|
size_t Chessgame::HashValue() const
|
|
{
|
|
size_t retval = 0;
|
|
MoveData movedata;
|
|
for(int i = 0; i < moves.Size(); i++){
|
|
moves.Get(i, movedata);
|
|
retval += movedata.IsCheck() +
|
|
movedata.GetStartFile() +
|
|
movedata.GetStartRow() +
|
|
movedata.GetEndFile() +
|
|
movedata.GetEndRow();
|
|
retval %= 0x8000000;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void Chessgame::CopyFrom( const Attribute* arg )
|
|
{
|
|
const Chessgame* game2 = (Chessgame*) arg;
|
|
SetDefined(game2->IsDefined());
|
|
strcpy( White, game2->White );
|
|
strcpy( Black, game2->Black );
|
|
strcpy( WhiteElo, game2->WhiteElo );
|
|
strcpy( BlackElo, game2->BlackElo );
|
|
strcpy( Event, game2->Event );
|
|
strcpy( Site, game2->Site );
|
|
strcpy( Date, game2->Date );
|
|
strcpy( ECO, game2->ECO );
|
|
strcpy( Result, game2->Result );
|
|
|
|
metainfo.clean();
|
|
for ( int i = 0; i < game2->metainfo.Size(); i++ )
|
|
{
|
|
MetainfoEntry newentry;
|
|
MetainfoEntry entry = game2->GetMetainfoEntry( i + 9 );
|
|
// added 9 because 9 metainfo fields are stored seperate datafields
|
|
strcpy( newentry.key, entry.key );
|
|
strcpy( newentry.value, entry.value );
|
|
metainfo.Append( newentry );
|
|
}
|
|
|
|
moves.clean();
|
|
for ( int i = 0; i < game2->moves.Size(); i++ )
|
|
{
|
|
MoveData newmove;
|
|
MoveData move = game2->GetMoveData( i );
|
|
newmove.startpos = move.startpos;
|
|
newmove.endpos = move.endpos;
|
|
newmove.newag = move.newag;
|
|
newmove.data = move.data;
|
|
moves.Append( newmove );
|
|
}
|
|
|
|
positions.clean();
|
|
for ( int i = 0; i < game2->positions.Size(); i++ )
|
|
{
|
|
Position newpos;
|
|
Position oldpos = game2->GetPositionData(i);
|
|
newpos.CopyFrom( &oldpos );
|
|
positions.Append( newpos );
|
|
}
|
|
}
|
|
|
|
Chessgame* Chessgame::Clone() const
|
|
{
|
|
Chessgame * chessgame = new Chessgame( 0, 0 );
|
|
|
|
strcpy( chessgame->White, White );
|
|
strcpy( chessgame->Black, Black );
|
|
strcpy( chessgame->WhiteElo, WhiteElo );
|
|
strcpy( chessgame->BlackElo, BlackElo );
|
|
strcpy( chessgame->Event, Event );
|
|
strcpy( chessgame->Site, Site );
|
|
strcpy( chessgame->Date, Date );
|
|
strcpy( chessgame->ECO, ECO );
|
|
strcpy( chessgame->Result, Result );
|
|
|
|
for ( int i = 0; i < metainfo.Size(); i++ )
|
|
chessgame->metainfo.Append( this->GetMetainfoEntry( i + 9 ) );
|
|
// added 9 because 9 metainfo fields are stored seperate datafields
|
|
|
|
for ( int i = 0; i < moves.Size(); i++ )
|
|
chessgame->moves.Append( this->GetMoveData( i ) );
|
|
|
|
for ( int i = 0; i < positions.Size(); i++ )
|
|
chessgame->positions.Append( this->GetPositionData( i ) );
|
|
|
|
return chessgame;
|
|
}
|
|
|
|
void Chessgame::WriteTo( char *dest ) const
|
|
{
|
|
*dest++ = IsDefined() ? '1' : '0';
|
|
strncpy(dest, &White[0], 49);
|
|
strncpy(dest, &Black[0], 49);
|
|
strncpy(dest, &WhiteElo[0], 6);
|
|
strncpy(dest, &BlackElo[0], 6);
|
|
strncpy(dest, &Event[0], 49);
|
|
strncpy(dest, &Site[0], 49);
|
|
strncpy(dest, &Date[0], 11);
|
|
strncpy(dest, &ECO[0], 7);
|
|
strncpy(dest, &Result[0], 49);
|
|
|
|
for (int i = 0; i < metainfo.Size(); i++)
|
|
{
|
|
MetainfoEntry entry;
|
|
metainfo.Get( i , entry );
|
|
strncpy( dest, entry.key, 13 );
|
|
strncpy( dest, entry.value, 49 );
|
|
}
|
|
|
|
for (int i = 0; i < moves.Size(); i++)
|
|
{
|
|
MoveData move;
|
|
moves.Get( i , move );
|
|
*dest++ = move.GetStartFile();
|
|
*dest++ = move.GetStartRow();
|
|
*dest++ = move.GetEndFile();
|
|
*dest++ = move.GetEndRow();
|
|
const string pgn = this->GetPGN(i + 1);
|
|
strncpy(dest, pgn.c_str(), 10);
|
|
}
|
|
}
|
|
|
|
void Chessgame::ReadFrom( const char *src )
|
|
{
|
|
SetDefined((*src++ == '1') ? true : false);
|
|
strncpy(&White[0], src, 49);
|
|
strncpy(&Black[0], src, 49);
|
|
strncpy(&WhiteElo[0], src, 6);
|
|
strncpy(&BlackElo[0], src, 6);
|
|
strncpy(&Event[0], src, 49);
|
|
strncpy(&Site[0], src, 49);
|
|
strncpy(&Date[0], src, 11);
|
|
strncpy(&ECO[0], src, 7);
|
|
strncpy(&Result[0], src, 49);
|
|
|
|
metainfo.clean();
|
|
for (int i = 0; i < metainfo.Size(); i++)
|
|
{
|
|
MetainfoEntry * entry = new MetainfoEntry();
|
|
strncpy( entry->key, src, 13 );
|
|
strncpy( entry->value, src, 49 );
|
|
metainfo.Append( *entry );
|
|
}
|
|
|
|
positions.clean();
|
|
moves.clean();
|
|
for (int i = 0; i < moves.Size(); i++)
|
|
{
|
|
char startfile = *src++;
|
|
char startrow = *src++;
|
|
char endfile = *src++;
|
|
char endrow = *src++;
|
|
char pgn[10];
|
|
strncpy(&pgn[0], src, 10);
|
|
AddMove(startfile, startrow, endfile, endrow, string(pgn));
|
|
}
|
|
}
|
|
|
|
SmiSize Chessgame::SizeOfChars() const
|
|
{
|
|
return ( 234 + (metainfo.Size() * 62) * (moves.Size() * 14));
|
|
}
|
|
|
|
int Chessgame::NumOfFLOBs() const
|
|
{
|
|
return 3;
|
|
}
|
|
|
|
Flob * Chessgame::GetFLOB( const int i )
|
|
{
|
|
switch ( i )
|
|
{
|
|
case 1:
|
|
return & metainfo;
|
|
|
|
case 2:
|
|
return &moves;
|
|
|
|
default:
|
|
return &positions;
|
|
}
|
|
}
|
|
|
|
void Chessgame::AddMetainfoEntry( string key, string value )
|
|
{
|
|
int len;
|
|
|
|
// do not store metainfos with empty keys
|
|
if ( key.size() == 0 )
|
|
return ;
|
|
|
|
switch ( key[ 0 ] )
|
|
{
|
|
case 'W' :
|
|
if ( key == "White" )
|
|
{
|
|
len = value.copy( White, 48, 0 );
|
|
White[ len ] = '\0';
|
|
return ;
|
|
}
|
|
else if ( key == "WhiteElo" )
|
|
{
|
|
len = value.copy( WhiteElo, 5, 0 );
|
|
WhiteElo[ len ] = '\0';
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'B' :
|
|
if ( key == "Black" )
|
|
{
|
|
len = value.copy( Black, 48, 0 );
|
|
Black[ len ] = '\0';
|
|
return ;
|
|
}
|
|
else if ( key == "BlackElo" )
|
|
{
|
|
len = value.copy( BlackElo, 5, 0 );
|
|
BlackElo[ len ] = '\0';
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'E' :
|
|
if ( key == "Event" )
|
|
{
|
|
len = value.copy( Event, 48, 0 );
|
|
Event[ len ] = '\0';
|
|
return ;
|
|
}
|
|
else if ( key == "ECO" )
|
|
{
|
|
len = value.copy( ECO, 6, 0 );
|
|
ECO[ len ] = '\0';
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'R' :
|
|
if ( key == "Result" )
|
|
{
|
|
len = value.copy( Result, 48, 0 );
|
|
Result[ len ] = '\0';
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'S' :
|
|
if ( key == "Site" )
|
|
{
|
|
len = value.copy( Site, 48, 0 );
|
|
Site[ len ] = '\0';
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'D' :
|
|
if ( key == "Date" )
|
|
{
|
|
len = value.copy( Date, 10, 0 );
|
|
Date[ len ] = '\0';
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
}
|
|
// key not found, thus tag pair will be stored in DBArrays metainfo
|
|
MetainfoEntry * entry = new MetainfoEntry();
|
|
|
|
// store key
|
|
len = key.copy( entry->key, 12, 0 );
|
|
entry->key[ len ] = '\0';
|
|
|
|
// store value
|
|
len = value.copy( entry->value, 48, 0 );
|
|
entry->value[ len ] = '\0';
|
|
|
|
// store metainfo entry
|
|
metainfo.Append( *entry );
|
|
}
|
|
|
|
void Chessgame::SortMetainfos()
|
|
{
|
|
metainfo.Sort( &MetainfoEntryCmp );
|
|
}
|
|
|
|
int Chessgame::AddMove( char startfile, char startrow,
|
|
char endfile, char endrow,
|
|
string pgn )
|
|
{
|
|
// cout << endl << "pgn Notation: " << pgn << endl;
|
|
Position * curpos = GetLastPosition( false );
|
|
MoveData * newmove = new MoveData();
|
|
newmove->SetStartFile( startfile );
|
|
newmove->SetStartRow( startrow );
|
|
newmove->SetEndFile( endfile );
|
|
newmove->SetEndRow( endrow );
|
|
newmove->SetCheck( pgn[ pgn.size() - 1 ] == '+' );
|
|
bool castling = false;
|
|
|
|
// calculate castling state
|
|
int startpos = newmove->GetStartPos();
|
|
int endpos = newmove->GetEndPos();
|
|
if ( ( startpos == 4 )
|
|
&& ( endpos == 6 )
|
|
&& ( curpos->gamefield[ startpos ] == WHITE_KING ) )
|
|
{
|
|
newmove->SetCastelling( KINGSIDE_CASTLING );
|
|
castling = true;
|
|
}
|
|
else if ( ( startpos == 4 )
|
|
&& ( endpos == 2 )
|
|
&& ( curpos->gamefield[ startpos ] == WHITE_KING ) )
|
|
{
|
|
newmove->SetCastelling( QUEENSIDE_CASTLING );
|
|
castling = true;
|
|
}
|
|
else if ( ( startpos == 60 )
|
|
&& ( endpos == 62 )
|
|
&& ( curpos->gamefield[ startpos ] == BLACK_KING ) )
|
|
{
|
|
newmove->SetCastelling( KINGSIDE_CASTLING );
|
|
castling = true;
|
|
}
|
|
else if ( ( startpos == 60 )
|
|
&& ( endpos == 58 )
|
|
&& ( curpos->gamefield[ startpos ] == BLACK_KING ) )
|
|
{
|
|
newmove->SetCastelling( QUEENSIDE_CASTLING );
|
|
castling = true;
|
|
}
|
|
string newAgent = DecodeAgent( curpos->gamefield[ startpos ] );
|
|
newmove->SetNewAgent( newAgent );
|
|
|
|
if (castling == false)
|
|
{
|
|
// White en passant capture
|
|
if ( startpos >= 32 && startpos <= 39 &&
|
|
( endpos == startpos + 7 || endpos == startpos + 9 ) &&
|
|
curpos->gamefield[ startpos ] == WHITE_PAWN &&
|
|
curpos->gamefield [ endpos ] == NONE &&
|
|
curpos->gamefield [ endpos - 8 ] == BLACK_PAWN )
|
|
{
|
|
newmove->SetEnPassant( true );
|
|
}
|
|
|
|
// Black en passant capture
|
|
else if ( startpos >= 24 && startpos <= 31 &&
|
|
( endpos == startpos - 7 || endpos == startpos - 9 ) &&
|
|
curpos->gamefield[ startpos ] == BLACK_PAWN &&
|
|
curpos->gamefield [ endpos ] == NONE &&
|
|
curpos->gamefield [ endpos + 8 ] == WHITE_PAWN )
|
|
{
|
|
newmove->SetEnPassant( true );
|
|
}
|
|
else
|
|
{
|
|
newmove->SetEnPassant( false );
|
|
}
|
|
|
|
string agent = DecodeAgentShort( curpos->gamefield[ startpos ] );
|
|
agent[ 0 ] = toupper( agent[ 0 ] );
|
|
|
|
if ( pgn[ 0 ] == agent[ 0 ] )
|
|
newmove->SetOutputAgent( true );
|
|
else
|
|
newmove->SetOutputAgent( false );
|
|
|
|
ostringstream endposstr;
|
|
endposstr << endfile << ( ( int ) endrow );
|
|
size_t pos = pgn.find( endposstr.str() );
|
|
bool ok = (pos != string::npos);
|
|
if (!ok) {
|
|
cout << "Could not find field <" << endposstr.str() << ">"
|
|
<< " in move <" << pgn << ">" << endl;
|
|
assert(false);
|
|
}
|
|
|
|
/*
|
|
ok = (pos > 0);
|
|
if (!ok) {
|
|
cout << "Found <" << endposstr.str() << ">"
|
|
<< "at pos=0 in move <" << pgn << ">" << endl;
|
|
assert(false);
|
|
}
|
|
*/
|
|
|
|
// check if the move captures an agent and remove the x symbol
|
|
if (pos > 0) {
|
|
pos--;
|
|
if ( pgn[ pos ] == 'x' )
|
|
pos--;
|
|
}
|
|
|
|
// check, if start row is contained in pgn notation
|
|
if ( pos >= 0 )
|
|
{
|
|
if ( ( pgn[ pos ] >= '1' ) && ( pgn[ pos ] <= '8' ) )
|
|
{
|
|
newmove->SetOutputRow( true );
|
|
pos--;
|
|
}
|
|
else
|
|
{
|
|
newmove->SetOutputRow( false );
|
|
}
|
|
}
|
|
|
|
// check, if start file is contained in pgn notation
|
|
if ( pos >= 0 )
|
|
{
|
|
if ( ( pgn[ pos ] >= 'a' ) && ( pgn[ pos ] <= 'h' ) )
|
|
{
|
|
newmove->SetOutputFile( true );
|
|
pos--;
|
|
}
|
|
else
|
|
{
|
|
newmove->SetOutputFile( false );
|
|
}
|
|
}
|
|
|
|
string newAgent;
|
|
pos = pgn.find( "=" );
|
|
if ( pos != string::npos )
|
|
{
|
|
newAgent += ( endrow == 8 ) ? pgn[ pos + 1 ] : tolower( pgn[ pos + 1 ] );
|
|
}
|
|
else
|
|
newAgent = DecodeAgent( curpos->gamefield[ startpos ] );
|
|
//cout << pgn << "," << pos << "," << newAgent << "\n";
|
|
newmove->SetNewAgent( newAgent );
|
|
|
|
} // end of !castling
|
|
|
|
// save move
|
|
moves.Append( *newmove );
|
|
|
|
// save current position after POS_STORE_INTERVALL moves
|
|
if ( ( moves.Size() > 0 ) && ( ( moves.Size() % POS_STORE_INTERVALL ) == 0 ) )
|
|
positions.Append( *curpos );
|
|
return true;
|
|
}
|
|
|
|
void Chessgame::GetMove( Move& result, int moveNumber )
|
|
{
|
|
if ( moveNumber < 1 )
|
|
moveNumber = 1;
|
|
else if ( moveNumber > moves.Size() + 1 )
|
|
moveNumber = moves.Size() + 1;
|
|
|
|
MoveData move;
|
|
moves.Get( moveNumber - 1, move );
|
|
|
|
Position* curpos = new Position();
|
|
GetPosition( curpos, moveNumber - 1, true, false );
|
|
|
|
// get captured id
|
|
char captured;
|
|
if ( !move.EnPassant() )
|
|
{
|
|
captured = curpos->gamefield [ (int)move.GetEndPos() ];
|
|
}
|
|
else
|
|
{
|
|
char agentID = curpos->gamefield [ (int)move.GetStartPos() ];
|
|
if ( agentID <= WHITE_KING )
|
|
captured = BLACK_PAWN;
|
|
else
|
|
captured = WHITE_PAWN;
|
|
}
|
|
|
|
// write data to result
|
|
result.moveNumber = moveNumber;
|
|
result.capturedID = ( captured );
|
|
result.agentID = curpos->gamefield [ (int)move.GetStartPos() ];
|
|
result.startFile = ( move.GetStartFile() );
|
|
result.startRow = ( move.GetStartRow() );
|
|
result.endFile = ( move.GetEndFile() );
|
|
result.endRow = ( move.GetEndRow() );
|
|
result.check = ( move.IsCheck() );
|
|
result.SetDefined( true );
|
|
|
|
// test of Move::WriteTo() and Move::ReadTo()
|
|
/*
|
|
char moveStr[result->SizeOfChars()];
|
|
result->WriteTo(&moveStr[0]);
|
|
result->moveNumber = 0;
|
|
result->agentID = 0;
|
|
result->capturedID = 0;
|
|
result->startFile = 'a';
|
|
result->startRow = 0;
|
|
result->endFile = 'a';
|
|
result->endRow = 0;
|
|
result->check = false;
|
|
result->defined = ( false );
|
|
result->ReadFrom(&moveStr[0]);
|
|
*/
|
|
}
|
|
|
|
Move Chessgame::GetMove( int moveNumber )
|
|
{
|
|
Move result;
|
|
GetMove( result, moveNumber );
|
|
return result;
|
|
}
|
|
|
|
void Chessgame::GetPosition( Position* result, int moveNumber,
|
|
bool loadGamefield, bool getMaterial ) const
|
|
{
|
|
// assertion: ( ( moveNumber >= 0 ) && ( moveNumber <= moves.Size() ) )
|
|
|
|
result->moveNumber = moveNumber;
|
|
int curmove;
|
|
|
|
// load last stored gamefield bevore moveNumber or initialize a new one
|
|
int posnum = ( int ) ( moveNumber / POS_STORE_INTERVALL );
|
|
if ( ( posnum == 0 ) || !loadGamefield )
|
|
{
|
|
result->StartPos();
|
|
curmove = 0;
|
|
}
|
|
else
|
|
{
|
|
Position pos = GetPositionData( posnum - 1 );
|
|
for ( int i = 0; i < 64; i++ )
|
|
result->gamefield[ i ] = pos.gamefield[ i ];
|
|
curmove = pos.moveNumber;
|
|
|
|
if ( getMaterial )
|
|
for ( int i = 0; i < 12; i++ )
|
|
result->material[ i ] = pos.material[ i ];
|
|
}
|
|
|
|
// calculate moves
|
|
while ( curmove < moveNumber )
|
|
{
|
|
MoveData currentMove = GetMoveData( curmove++ );
|
|
result->MakeMove(
|
|
currentMove.GetStartPos(),
|
|
currentMove.GetEndPos(),
|
|
currentMove.GetNewAgentID(),
|
|
currentMove.GetCastling() );
|
|
}
|
|
|
|
result->SetDefined(IsDefined());
|
|
|
|
// test of Position::WriteTo() and Position::ReadTo()
|
|
/*
|
|
char posStr[result->SizeOfChars()];
|
|
result->WriteTo(&posStr[0]);
|
|
for ( int i = 0; i < 64; i++ )
|
|
{
|
|
result->gamefield[ i ] = 0;
|
|
}
|
|
for ( int i = 0; i < 12; i++ )
|
|
{
|
|
result->material[ i ] = 0;
|
|
}
|
|
result->defined = ( false );
|
|
result->ReadFrom(&posStr[0]);
|
|
*/
|
|
}
|
|
|
|
Position* Chessgame::GetPosition( int moveNumber )
|
|
{
|
|
Position * result = new Position();
|
|
GetPosition( result, moveNumber, false );
|
|
return result;
|
|
}
|
|
|
|
Position* Chessgame::GetLastPosition( bool loadGamefield )
|
|
{
|
|
Position * result = new Position();
|
|
GetPosition( result, moves.Size(), loadGamefield );
|
|
return result;
|
|
}
|
|
|
|
const string Chessgame::GetPGN( int moveNumber ) const
|
|
{
|
|
if ( moveNumber < 1 )
|
|
moveNumber = 1;
|
|
else if ( moveNumber > moves.Size() + 1 )
|
|
moveNumber = moves.Size() + 1;
|
|
|
|
|
|
string result;
|
|
Position* curpos = new Position();
|
|
GetPosition( curpos, moveNumber - 1 );
|
|
|
|
|
|
MoveData move;
|
|
moves.Get( moveNumber - 1, move );
|
|
|
|
int startpos = move.GetStartPos();
|
|
int endpos = move.GetEndPos();
|
|
|
|
if ( move.GetCastling() )
|
|
{
|
|
if ( move.GetCastling() == QUEENSIDE_CASTLING )
|
|
result = "O-O-O";
|
|
else
|
|
result = "O-O";
|
|
}
|
|
else
|
|
{
|
|
if ( move.OutputAgent() )
|
|
{
|
|
string agstr = DecodeAgentShort( curpos->gamefield[ startpos ] );
|
|
agstr[ 0 ] = toupper( agstr[ 0 ] );
|
|
result += agstr;
|
|
}
|
|
|
|
if ( move.OutputFile() )
|
|
{
|
|
result += move.GetStartFile();
|
|
}
|
|
|
|
if ( move.OutputRow() )
|
|
{
|
|
ostringstream row;
|
|
row << ( int ) ( move.GetStartRow() );
|
|
result += row.str();
|
|
}
|
|
|
|
if ( ( curpos->gamefield[ endpos ] & 0x07 ) != NONE )
|
|
{
|
|
result += 'x';
|
|
}
|
|
|
|
// append endfile and endrow
|
|
result += move.GetEndFile();
|
|
ostringstream row;
|
|
row << ( int ) ( move.GetEndRow() );
|
|
result += row.str();
|
|
|
|
if ( DecodeAgentShort( curpos->gamefield[ startpos ] ) !=
|
|
move.GetNewAgent() )
|
|
{
|
|
result += '=';
|
|
string agstr = move.GetNewAgent();
|
|
agstr[ 0 ] = toupper( agstr[ 0 ] );
|
|
result += agstr;
|
|
}
|
|
}
|
|
|
|
if ( move.IsCheck() )
|
|
result += '+';
|
|
|
|
return result;
|
|
}
|
|
|
|
void Chessgame::GetMetainfoValue( string key, STRING_T* result )
|
|
{
|
|
if ( key.size() == 0 )
|
|
{
|
|
string err = "Missing key!";
|
|
strcpy ( *result, err.c_str() );
|
|
}
|
|
if ( isupper( key[ 0 ] ) )
|
|
{ // search for pgn-notation key values
|
|
switch ( key[ 0 ] )
|
|
{
|
|
case 'W' :
|
|
if ( key == "White" )
|
|
{
|
|
strcpy ( *result, White );
|
|
return ;
|
|
}
|
|
else if ( key == "WhiteElo" )
|
|
{
|
|
strcpy ( *result, WhiteElo );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'B' :
|
|
if ( key == "Black" )
|
|
{
|
|
strcpy ( *result, Black );
|
|
return ;
|
|
}
|
|
else if ( key == "BlackElo" )
|
|
{
|
|
strcpy ( *result, BlackElo );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'E' :
|
|
if ( key == "Event" )
|
|
{
|
|
strcpy ( *result, Event );
|
|
return ;
|
|
}
|
|
else if ( key == "ECO" )
|
|
{
|
|
strcpy ( *result, ECO );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'S' :
|
|
if ( key == "Site" )
|
|
{
|
|
strcpy ( *result, Site );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'D' :
|
|
if ( key == "Date" )
|
|
{
|
|
strcpy ( *result, Date );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'R' :
|
|
if ( key == "Result" )
|
|
{
|
|
strcpy ( *result, Result );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
else
|
|
{ // search for chessgameAlgebra-notation key values
|
|
switch ( key[ 0 ] )
|
|
{
|
|
case 'n' :
|
|
if ( key == "name_w" )
|
|
{
|
|
strcpy ( *result, White );
|
|
return ;
|
|
}
|
|
else if ( key == "name_b" )
|
|
{
|
|
strcpy ( *result, Black );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'd' :
|
|
if ( key == "date" )
|
|
{
|
|
strcpy ( *result, Date );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 's' :
|
|
if ( key == "site" )
|
|
{
|
|
strcpy ( *result, Site );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'e' :
|
|
if ( key == "event" )
|
|
{
|
|
strcpy ( *result, Event );
|
|
return ;
|
|
}
|
|
else if ( key == "eco_code" )
|
|
{
|
|
strcpy ( *result, ECO );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'r' :
|
|
if ( key == "result" )
|
|
{
|
|
strcpy ( *result, Result );
|
|
return ;
|
|
}
|
|
else if ( key == "rating_w" )
|
|
{
|
|
strcpy ( *result, WhiteElo );
|
|
return ;
|
|
}
|
|
else if ( key == "rating_b" )
|
|
{
|
|
strcpy ( *result, BlackElo );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case 'm' :
|
|
if ( key == "moves" )
|
|
{
|
|
sprintf( *result, "%d", moves.Size() );
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
// key not found, thus tag pair will be searched in DBArrays metainfo
|
|
int len, pos;
|
|
|
|
// create new MetainfoEntry object as search key
|
|
MetainfoEntry * mi_key = new MetainfoEntry();
|
|
len = key.copy( mi_key->key, 12, 0 );
|
|
mi_key->key[ len ] = '\0';
|
|
|
|
// search mi_key and copy value to result STRING, if found
|
|
if ( metainfo.Find( mi_key, &MetainfoEntryCmp, pos ) )
|
|
{
|
|
MetainfoEntry entry;
|
|
metainfo.Get( pos , entry );
|
|
strcpy( *result, ( entry.value ) );
|
|
}
|
|
else
|
|
{
|
|
string err = "key " + key + " not found";
|
|
strcpy ( *result, err.c_str() );
|
|
}
|
|
}
|
|
|
|
MetainfoEntry Chessgame::GetMetainfoEntry( int i ) const
|
|
{
|
|
int len;
|
|
string key, value;
|
|
|
|
if ( i > GetMetainfoCount() )
|
|
{
|
|
MetainfoEntry entry;
|
|
key = "undef";
|
|
value = "undef";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
len = value.copy( entry.value, 48, 0 );
|
|
entry.value[ len ] = '\0';
|
|
return entry;
|
|
}
|
|
else if ( i < 9 )
|
|
{
|
|
MetainfoEntry entry;
|
|
switch ( i )
|
|
{
|
|
case 0:
|
|
key = "White";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, White );
|
|
break;
|
|
case 1:
|
|
key = "Black";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, Black );
|
|
break;
|
|
case 2:
|
|
key = "WhiteElo";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, WhiteElo );
|
|
break;
|
|
case 3:
|
|
key = "BlackElo";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, BlackElo );
|
|
break;
|
|
case 4:
|
|
key = "Event";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, Event );
|
|
break;
|
|
case 5:
|
|
key = "Site";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, Site );
|
|
break;
|
|
case 6:
|
|
key = "Date";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, Date );
|
|
break;
|
|
case 7:
|
|
key = "ECO";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, ECO );
|
|
break;
|
|
case 8:
|
|
key = "Result";
|
|
len = key.copy( entry.key, 12, 0 );
|
|
entry.key[ len ] = '\0';
|
|
strcpy ( entry.value, Result );
|
|
break;
|
|
}
|
|
return entry;
|
|
}
|
|
else
|
|
{
|
|
MetainfoEntry entry;
|
|
metainfo.Get( i - 9, entry );
|
|
return entry;
|
|
}
|
|
}
|
|
|
|
/*
|
|
3.5 Class MovingChessPiece
|
|
|
|
*/
|
|
MovingChessPiece::~MovingChessPiece()
|
|
{
|
|
//delete moveDuration;
|
|
//(&mpoint)->Destroy(); // calls Destroy member function of class Mapping
|
|
}
|
|
/*
|
|
this is the standard constructor used to create each piece's startposition
|
|
|
|
*/
|
|
MovingChessPiece::MovingChessPiece( string k, string file,
|
|
int row , const double CreationTime,
|
|
const DateTime* movedur ) :
|
|
kind( k ),
|
|
movedInLastInterval( false ),
|
|
startrow( row ),
|
|
moveDuration( durationtype ),
|
|
startInstant( instanttype ),
|
|
endInstant( instanttype ),
|
|
iv( startInstant, endInstant, true, true ),
|
|
mpoint( 10 ),
|
|
upoint( iv, 0, 0, 0, 0 )
|
|
{
|
|
isWhite = ( kind[ 0 ] == toupper( kind[ 0 ] ) );
|
|
startfile = tolower( file[ 0 ] );
|
|
actfile = startfile;
|
|
actrow = row;
|
|
mpoint.Clear();
|
|
mpoint.StartBulkLoad();
|
|
moveDuration.Equalize(movedur);
|
|
startInstant.ReadFrom( CreationTime );
|
|
endInstant = startInstant;
|
|
upoint.timeInterval.start = startInstant;
|
|
upoint.timeInterval.end = endInstant;
|
|
x0 = ( double ) ( file[ 0 ] - 'a' + 1 );
|
|
y0 = ( double ) row;
|
|
if ( (isWhite && (startrow==8)) ||
|
|
(!isWhite && (startrow==1)) ) // this was a pawn's promotion
|
|
{
|
|
x0 += -0.25;
|
|
y0 += -0.25;
|
|
}
|
|
upoint.p0.Set( x0, y0 );
|
|
x1 = x0;
|
|
y1 = y0;
|
|
upoint.p1.Set( x1, y1 );
|
|
mpoint.Add( upoint );
|
|
upoint.timeInterval.lc = false;
|
|
}
|
|
|
|
/*
|
|
extendInterval extends the interval of the newest upoint by the as exttime specified duration.
|
|
If the piece wasn't moved in the last half move, the upoint's interval is extended,
|
|
otherwise a new upoint is created
|
|
|
|
*/
|
|
|
|
void MovingChessPiece::extendInterval(const DateTime* exttime)
|
|
{
|
|
upoint.timeInterval.start = upoint.timeInterval.end;
|
|
// new interval end is specified time later
|
|
upoint.timeInterval.end.Add( exttime );
|
|
if ( movedInLastInterval ) // if piece was moved in last interval
|
|
{
|
|
upoint.p0.Set( upoint.p1.GetX(), upoint.p1.GetY() ); // create new UPoint
|
|
mpoint.Add( upoint );
|
|
}
|
|
else mpoint.MergeAdd( upoint ); // otherwise try to extend last UPoint
|
|
movedInLastInterval = false;
|
|
}
|
|
|
|
/*
|
|
|
|
adjustTime extends the interval of the newest upoint to the as parameter specified instant.
|
|
If the piece wasn't moved in the last half move, the upoint's interval is extended,
|
|
otherwise a new upoint is created
|
|
|
|
*/
|
|
|
|
void MovingChessPiece::adjustTime(const Instant newEndInstant)
|
|
{
|
|
if (upoint.timeInterval.end==newEndInstant) return;
|
|
// former interval end is new start
|
|
upoint.timeInterval.start = upoint.timeInterval.end;
|
|
// new interval end is specified time
|
|
upoint.timeInterval.end = newEndInstant;
|
|
|
|
|
|
if ( movedInLastInterval ) // if piece was moved in last interval
|
|
{
|
|
//cout << "adjust time " << upoint.timeInterval.start
|
|
// << " ~ " << upoint.timeInterval.end << endl;
|
|
upoint.p0.Set( upoint.p1.GetX(), upoint.p1.GetY() ); // create new UPoint
|
|
mpoint.Add( upoint );
|
|
}
|
|
else mpoint.MergeAdd( upoint ); // otherwise try to extend last UPoint
|
|
movedInLastInterval = false;
|
|
}
|
|
|
|
/*
|
|
appendMove is the normal function that moves a piece after the normal delay time
|
|
|
|
*/
|
|
|
|
void MovingChessPiece::appendMove ( string newfile,
|
|
int newrow, bool TargetOffset )
|
|
{
|
|
// last interval end is new interval start
|
|
upoint.timeInterval.start = upoint.timeInterval.end;
|
|
upoint.timeInterval.end.Add( &moveDuration );
|
|
upoint.p0.Set( upoint.p1.GetX(), upoint.p1.GetY() );
|
|
upoint.p1.Set( (double) ( tolower( newfile[0] ) - 'a' + 1 ),
|
|
( double ) newrow );
|
|
if (TargetOffset) upoint.p1.Set( 0.25+upoint.p1.GetX(),
|
|
0.25+upoint.p1.GetY() );
|
|
//cout << kind << actfile << actrow << newfile << newrow;
|
|
mpoint.Add( upoint );
|
|
actfile = tolower( newfile[ 0 ] );
|
|
actrow = newrow;
|
|
movedInLastInterval = true;
|
|
}
|
|
|
|
/*
|
|
applyCastelling moves the rook besides the king after this has moved more than one field away
|
|
|
|
*/
|
|
|
|
void MovingChessPiece::applyCastelling ()
|
|
{
|
|
if ( startfile == "a" ) appendMove( "d", actrow , false);
|
|
else appendMove( "f", actrow , false);
|
|
}
|
|
|
|
/*
|
|
removePiece removes a captured piece after waiting in place for
|
|
the normale delay time
|
|
and the duration of the capturing piece's move
|
|
|
|
*/
|
|
|
|
void MovingChessPiece::removePiece ()
|
|
{
|
|
// last interval end is new interval start
|
|
upoint.timeInterval.start = upoint.timeInterval.end;
|
|
upoint.timeInterval.end.Add( &moveDuration );
|
|
upoint.p0.Set( upoint.p1.GetX(), upoint.p1.GetY() );
|
|
if ( isWhite ) y1 = -2.0;
|
|
else y1 = 2.0;
|
|
upoint.p1.Set( ( double ) ( startfile[ 0 ] - 'a' + 1 ),
|
|
( double ) startrow + y1 );
|
|
mpoint.Add( upoint );
|
|
actfile = "";
|
|
actrow = 0;
|
|
movedInLastInterval = true;
|
|
//cout << " x ";
|
|
}
|
|
|
|
/*
|
|
centerPiece positions the piece in the center of the field, i.e. to the
|
|
nearest integer coordinates; use this function e.g. after the removal of a captured piece
|
|
|
|
*/
|
|
void MovingChessPiece::centerPiece ()
|
|
{
|
|
upoint.timeInterval.start = upoint.timeInterval.end;
|
|
upoint.timeInterval.end.Add( &moveDuration );
|
|
upoint.p0.Set( upoint.p1.GetX(), upoint.p1.GetY() );
|
|
upoint.p1.Set( floor(upoint.p0.GetX() + 0.5),
|
|
floor(upoint.p1.GetY() + 0.5) );
|
|
mpoint.Add( upoint );
|
|
movedInLastInterval = true;
|
|
}
|
|
|
|
const string MovingChessPiece::getActFile()
|
|
{ return actfile;}
|
|
|
|
const int MovingChessPiece::getActRow()
|
|
{ return actrow;}
|
|
|
|
const string* MovingChessPiece::getKind()
|
|
{ return & kind;}
|
|
|
|
bool* MovingChessPiece::trueIsWhite()
|
|
{ return & isWhite;}
|
|
|
|
MPoint* MovingChessPiece::getMPoint()
|
|
{ return & mpoint;}
|
|
|
|
const double MovingChessPiece::getCurrentTime()
|
|
{ return upoint.timeInterval.end.ToDouble();}
|
|
|
|
void MovingChessPiece::closeMPoint()
|
|
{
|
|
if ( kind == AGENT_NAMES[ UNDEF ] ) return ;
|
|
/*
|
|
bool result = true;
|
|
const UPoint *lastunit, *unit;
|
|
int k = 0, j = 0;
|
|
for (k=0;k<i;k++)
|
|
{
|
|
mpoint.Get(k, unit);
|
|
if (unit->IsValid()) coutNewInterval(unit);
|
|
else cout << "unit " << k << " in mpoint is invalid";
|
|
}
|
|
if( i == 1 )
|
|
{
|
|
mpoint.Get( 0, unit );
|
|
result = ( unit->IsValid() );
|
|
}
|
|
else for( k = 1; k < i; k++ )
|
|
{
|
|
mpoint.Get( k-1, lastunit );
|
|
if( !lastunit->IsValid() )
|
|
{
|
|
result = false;
|
|
j=-1;
|
|
break;
|
|
}
|
|
mpoint.Get( k, unit );
|
|
if( !unit->IsValid() )
|
|
{
|
|
result = false;
|
|
break;
|
|
}
|
|
if( (!lastunit->Disjoint( *unit )) &&
|
|
(!lastunit->TU_Adjacent( *unit )) )
|
|
{
|
|
result = false;
|
|
j=1;
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
mpoint.EndBulkLoad( true );
|
|
}
|
|
|
|
void MovingChessPiece::coutNewInterval( UPoint* up )
|
|
{
|
|
cout << "Interval: "
|
|
<< up->timeInterval.start.GetHour() << ":"
|
|
<< up->timeInterval.start.GetMinute() << ":"
|
|
<< up->timeInterval.start.GetSecond() << ":"
|
|
<< up->timeInterval.start.GetMillisecond() << " - "
|
|
<< up->timeInterval.end.GetHour() << ":"
|
|
<< up->timeInterval.end.GetMinute() << ":"
|
|
<< up->timeInterval.end.GetSecond() << ":"
|
|
<< up->timeInterval.end.GetMillisecond() << endl;
|
|
}
|
|
|
|
void MovingChessPiece::coutNewInterval( const UPoint* up )
|
|
{
|
|
cout << "Interval: "
|
|
<< up->timeInterval.start.GetHour() << ":"
|
|
<< up->timeInterval.start.GetMinute() << ":"
|
|
<< up->timeInterval.start.GetSecond() << ":"
|
|
<< up->timeInterval.start.GetMillisecond() << " " << up->p0 << " - "
|
|
<< up->timeInterval.end.GetHour() << ":"
|
|
<< up->timeInterval.end.GetMinute() << ":"
|
|
<< up->timeInterval.end.GetSecond() << ":"
|
|
<< up->timeInterval.end.GetMillisecond() << " " << up->p1 << " " << endl;
|
|
}
|
|
/*
|
|
3.6 Class MovingChessPieces
|
|
|
|
*/
|
|
MovingChessPieces::MovingChessPieces() :
|
|
startOfGame(instanttype),
|
|
iv(startOfGame, startOfGame, true, true),
|
|
upref(iv, 0, 0, 0, 0)
|
|
{
|
|
waitBeforeMoveDuration = new DateTime ( 0, 2000, durationtype );
|
|
moveDuration = new DateTime ( 0, 1000, durationtype );
|
|
totalMoveDuration = new DateTime ( 0, 5000, durationtype );
|
|
waitAfterMoveDuration = new DateTime ( 0, 1000, durationtype );
|
|
startOfGame.Set( 2007, 1, 1, 9, 0, 0, 0 ); // 1.1.2007 9 Uhr
|
|
upref.timeInterval.start = startOfGame;
|
|
upref.timeInterval.end = startOfGame;
|
|
|
|
mcp[ 00 ] = new MovingChessPiece( "King", "e", 1 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
// King must be first for castelling
|
|
mcp[ 01 ] = new MovingChessPiece( "Rook", "a", 1 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
// Rooks must be next for castelling
|
|
mcp[ 02 ] = new MovingChessPiece( "Rook", "h", 1 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 03 ] = new MovingChessPiece( "Pawn", "a", 2 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 04 ] = new MovingChessPiece( "Pawn", "b", 2 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 05 ] = new MovingChessPiece( "Pawn", "c", 2 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 06 ] = new MovingChessPiece( "Pawn", "d", 2 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 07 ] = new MovingChessPiece( "Pawn", "e", 2 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 8 ] = new MovingChessPiece( "Pawn", "f", 2 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 9 ] = new MovingChessPiece( "Pawn", "g", 2 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 10 ] = new MovingChessPiece( "Pawn", "h", 2 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 11 ] = new MovingChessPiece( "Knight", "b", 1 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 12 ] = new MovingChessPiece( "Knight", "g", 1 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 13 ] = new MovingChessPiece( "Bishop", "c", 1 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 14 ] = new MovingChessPiece( "Bishop", "f", 1 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 15 ] = new MovingChessPiece( "Queen", "d", 1 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 16 ] = new MovingChessPiece( "king", "e", 8 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
// king must be first for castling
|
|
mcp[ 17 ] = new MovingChessPiece( "rook", "a", 8 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
// rooks must be next for castling
|
|
mcp[ 18 ] = new MovingChessPiece( "rook", "h", 8 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 19 ] = new MovingChessPiece( "pawn", "a", 7 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 20 ] = new MovingChessPiece( "pawn", "b", 7 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 21 ] = new MovingChessPiece( "pawn", "c", 7 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 22 ] = new MovingChessPiece( "pawn", "d", 7 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 23 ] = new MovingChessPiece( "pawn", "e", 7 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 24 ] = new MovingChessPiece( "pawn", "f", 7 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 25 ] = new MovingChessPiece( "pawn", "g", 7 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 26 ] = new MovingChessPiece( "pawn", "h", 7 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 27 ] = new MovingChessPiece( "knight", "b", 8 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 28 ] = new MovingChessPiece( "knight", "g", 8 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 29 ] = new MovingChessPiece( "bishop", "c", 8 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 30 ] = new MovingChessPiece( "bishop", "f", 8 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
mcp[ 31 ] = new MovingChessPiece( "queen", "d", 8 ,
|
|
startOfGame.ToDouble() ,
|
|
moveDuration );
|
|
for ( i = 32;i < 48;i++ ) mcp[ i ] = new MovingChessPiece();
|
|
MPointWriteNextCount = 0;
|
|
}
|
|
|
|
MovingChessPieces::~MovingChessPieces()
|
|
{
|
|
//for ( i = 0;i < 48;i++ ) delete mcp[ i ];
|
|
}
|
|
|
|
void MovingChessPieces::realizeMove( Move* mv, const MoveData* mvdata )
|
|
{
|
|
//cout << "MovingChessPieces::realizeMove entered" << endl;
|
|
//cout << mv->GetMoveNumber() << " - " << mv->GetAgent()<< ": "
|
|
// << mv->GetStartFile() << mv->GetStartRow() << "-"
|
|
// << mv->GetEndFile() << mv->GetEndRow() << endl;
|
|
upref.timeInterval.end.Add(totalMoveDuration);
|
|
for ( i = 0;i < 48;i++ )
|
|
{
|
|
if ( *( mcp[i]->getKind() ) == AGENT_NAMES[ UNDEF ] )
|
|
continue; //this mcp wasn't used yet
|
|
|
|
if ( mcp[i]->getActRow() == mv->GetStartRow() &&
|
|
(mcp[i]->getActFile())[0] == tolower((mv->GetStartFile())[0]))
|
|
{ // this mcp represents the piece being moved,
|
|
// detect if another piece was captured
|
|
for ( j = 0;j < 48;j++ )
|
|
{
|
|
if ( *( mcp[j]->getKind() ) == AGENT_NAMES[ UNDEF ] )
|
|
continue; //this mcp wasn't used yet
|
|
|
|
if ( mcp[j]->getActRow() == mv->GetEndRow() &&
|
|
(mcp[j]->getActFile())[0] == tolower((mv->GetEndFile())[0]) )
|
|
{
|
|
mcp[j]->extendInterval(waitBeforeMoveDuration);
|
|
mcp[j]->extendInterval(moveDuration);
|
|
mcp[j]->removePiece();
|
|
// this mcp represents the piece being captured
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j<48)
|
|
TargetOffset = true; // another piece was captured, step besides of it
|
|
else
|
|
TargetOffset = false;
|
|
|
|
// next lines recognize a pawn's
|
|
// promotion when it reaches the other baseline
|
|
if ( ( *( mcp[i]->getKind() ) == "Pawn" && mv->GetEndRow() == 8 )
|
|
|| ( *( mcp[i]->getKind() ) == "pawn" && mv->GetEndRow() == 1 ) )
|
|
{
|
|
|
|
// remove the pawn
|
|
mcp[i]->extendInterval(waitBeforeMoveDuration);
|
|
mcp[i]->appendMove( mv->GetEndFile(),
|
|
mv->GetEndRow(), TargetOffset );
|
|
mcp[i]->removePiece();
|
|
|
|
// create a new moving piece
|
|
|
|
// find unused mcp
|
|
for ( j = 32;j < 48;j++ ) {
|
|
if ( *(mcp[j]->getKind())==AGENT_NAMES[UNDEF] ) break; }
|
|
cout << "unused mcp: " << j
|
|
<< ", ptr " << (void*) mcp[j] << endl;
|
|
delete mcp[j];
|
|
mcp[j] = new MovingChessPiece(
|
|
AGENT_NAMES[(int)mvdata->GetNewAgentID()],
|
|
mv->GetEndFile(), mv->GetEndRow(),
|
|
mcp[i]->getCurrentTime() , moveDuration );
|
|
|
|
mcp[j]->centerPiece(); // and put the officer in the fields's center
|
|
}
|
|
else
|
|
{
|
|
// move wasn't pawn's promotion, execute move
|
|
mcp[i]->extendInterval(waitBeforeMoveDuration);
|
|
mcp[i]->appendMove( mv->GetEndFile() , mv->GetEndRow() , TargetOffset );
|
|
|
|
if (TargetOffset)
|
|
mcp[i]->centerPiece(); // if another piece was captured
|
|
|
|
// next lines recognize castelling
|
|
//if the king was moved over more than one file
|
|
if ( ( *( mcp[i]->getKind() ) == "King" ||
|
|
*( mcp[i] ->getKind() ) == "king" )
|
|
&& ( abs( (mv->GetEndFile())[0] - (mv->GetStartFile())[0] ) > 1 )
|
|
)
|
|
{ // castelling! look which rook has to move
|
|
if ( ( mv->GetEndFile() ) [ 0 ] == 'g' )
|
|
j = 2; // white kingside rook
|
|
else
|
|
j = 1; // white queenside rook
|
|
if ( mv->GetStartRow() == 8 )
|
|
j += 16; // black rooks
|
|
|
|
mcp[j]->extendInterval(waitBeforeMoveDuration);
|
|
mcp[j]->extendInterval(moveDuration);
|
|
mcp[j]->applyCastelling();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for ( int i = 0;i < 48;i++ )
|
|
{
|
|
if (! (*(mcp[i]->getKind()) == AGENT_NAMES[UNDEF]))
|
|
mcp[i]->adjustTime(upref.timeInterval.end);
|
|
// for mcps representing pieces not moved
|
|
}
|
|
}
|
|
|
|
const bool MovingChessPieces::isValid( int i )
|
|
{ return !( *( mcp[ i ] ->getKind() ) == AGENT_NAMES[ UNDEF ] ); }
|
|
|
|
MovingChessPiece* MovingChessPieces::getMovingChessPiece( int i )
|
|
{ return mcp[ i ]; }
|
|
|
|
void MovingChessPieces::incMPointWriteNextCount()
|
|
{MPointWriteNextCount++;}
|
|
|
|
int MovingChessPieces::getMPointWriteNextCount()
|
|
{ return MPointWriteNextCount;}
|
|
|
|
void MovingChessPieces::setTupleTypeRemember( TupleType* tt )
|
|
{TupleTypeRemember = tt;}
|
|
|
|
TupleType* MovingChessPieces::getTupleTypeRemember() {
|
|
return TupleTypeRemember;
|
|
}
|
|
|
|
void MovingChessPieces::closeMPoints()
|
|
{
|
|
//cout << "MovingChessPieces::closeMPoints entered" << endl;
|
|
for ( i = 0;i < 48;i++ ) mcp[ i ] ->closeMPoint(); }
|
|
|
|
} // namespace ChessAlgebra
|