//
// C++ Interface: globals
//
// Description:
//
//
// Author: Hendrik Hochstetter <hochsthk@studi.informatik.uni-stuttgart.de>, (C) 2008
//
// Copyright: See COPYING file that comes with this distribution
//
//
/**
* Typdeklarationen für Typen, die in allen anderen Programmteilen Anwendung finden.
**/
#ifndef _CHESSPPAI_GLOBALS_H
#define _CHESSPPAI_GLOBALS_H
#include <QtCore/QString>
#include <QtCore/QHash>
typedef struct {
/** maximale Anzahl an AiPlayer threads, die parallel laufen dürfen **/
int maxthreads;
/** minimale garantierte Suchtiefe **/
int mindepth;
/** maximale Suchtiefe, falls minimale nicht ausreicht um eine ruhige Stellung zu erreichen **/
int maxdepth;
/** wartezeit (in s), bis der AiManager auf dem Server schaut ob es wieder was zu tun gibt **/
int refreshrate;
/** maximale Rechenzeit pro Zug (in s), danach wird abgebrochen und der bis dahin beste Zug ausgewählt **/
int maxtime;
/** der Server, auf dem sich die KI einloggen und spielen soll **/
QString server;
int port;
QString password;
QString username;
} AiSettings;
//! statusinformationen.
enum AiStatus {
NotConnected = 0x0,
Trying = 0x1,
Connected = 0x02, // verbindung steht
LoggedIn = 0x04, // eingeloggt
Chpwd = 0x08, // warten auf antwort nach chpwd command
Game = 0x10, // in einem spiel
White = 0x20,
Black = 0x40,
Transferring = 0x80,
GameListRequested = 0x100,
KeepAlive = 0x200 // verbindung soll aufrecht erhalten werden (für rechenphase der ki)
};
typedef enum {
PAWN_0 = 0x01,
PAWN_1 = 0x02,
PAWN_2 = 0x04,
PAWN_3 = 0x08,
PAWN_4 = 0x010,
PAWN_5 = 0x020,
PAWN_6 = 0x040,
PAWN_7 = 0x080,
CASTLE_LONG = 0x0100,
CASTLE_SHORT = 0x0200
} NodeState;
typedef enum {
EMPTY = 0,
// weisse figuren
PAWN_W = 2,
BISHOP_W = 3,
KNIGHT_W = 4,
ROOK_W = 5,
QUEEN_W = 6,
KING_W = 7,
// schwarze figuren
PAWN_B=-2,
BISHOP_B=-3,
KNIGHT_B=-4,
ROOK_B=-5,
QUEEN_B=-6,
KING_B=-7
} Piece;
typedef enum {
// figuren
PAWN = 2,
BISHOP = 3,
KNIGHT = 4,
ROOK = 5,
QUEEN = 6,
KING = 7
} UncolouredPiece;
typedef int MoveVector;
typedef int Field;
typedef enum {
NONE = 0, // leeres Feld
WHITE = 1,
BLACK = -1
} Colour;
inline Colour colourOfPiece (Piece piece)
{
Colour c = NONE;
switch (piece)
{
case PAWN_W:
case BISHOP_W:
case KNIGHT_W:
case ROOK_W:
case QUEEN_W:
case KING_W:
c = WHITE;
break;
case PAWN_B:
case BISHOP_B:
case KNIGHT_B:
case ROOK_B:
case QUEEN_B:
case KING_B:
c = BLACK;
break;
};
return c;
};
//typedef QHash<Field,Piece> Position;
/**
* @brief Eigene kleine Containerklasse zum Speichern von Spielstellungen
* @details Einträge werden in 2 arrays gespeichert, eins aus Field und eins aus Piece
* jeweils mit 32 Einträgen. weiße Pieces werden von unten 0..15 eingefügt, schwarze von
* oben. Für einfügen, Lookup von Feldern für Pieces etc. muss maximal die Hälfte der Arrays
* durchsucht werden. Verkürzt die Rechenzeit im Vergleich zu QHash ca. um den Faktor 5.
**/
/** @TODO schneller, wenn nicht jedesmal schauen ob field == 0 und dafür durch alle 32 elemente laufen?
**/
struct Position
{
//public:
Field fields[32];
Piece pieces[32];
Position (const Position &p)
{
fields [0] = 0;
fields [31] = 0;
for (int i = 0; i < 16; i++)
{
// nur kopieren, was wirklich daten enthält.
if (p.fields [i] == 0)
{
fields [i] = 0;
break;
}
fields [i] = p.fields [i];
pieces [i] = p.pieces [i];
}
for (int i = 31; i > 15; i--)
{
// nur kopieren, was wirklich daten enthält.
if (p.fields [i] == 0)
{
fields [i] = 0;
break;
}
fields [i] = p.fields [i];
pieces [i] = p.pieces [i];
}
};
Position () {
// nur vorne und hinten muss initialisiert werden. dass dazwischen nix ist ist dann klar.
fields [0] = 0;
fields [31] = 0;
};
/** einzelnes elementchen löschen **/
inline void remove (Field f)
{
int from = 16;
for (int i = 0; i < 16; i++)
{
if (fields [i] == 0)
{
break;
}
else if (fields [i] == f)
{
from = i;
break;
}
}
for (int i = from; i < 15; i++)
{
fields [i] = fields [i + 1];
pieces [i] = pieces [i + 1];
if (fields [i] == 0)
{
break;
}
}
if (from != 16)
{
fields [15] = 0;
}
from = 15;
for (int i = 31; i > 15; i--)
{
if (fields [i] == 0)
{
break;
}
else if (fields [i] == f)
{
from = i;
break;
}
}
for (int i = from; i > 16; i--)
{
fields [i] = fields [i - 1];
pieces [i] = pieces [i - 1];
if (fields [i] == 0)
{
break;
}
}
if (from != 15)
{
fields [16] = 0;
}
};
/** anzahl der einträge in Position **/
inline const int size ()
{
int size = 0;
for (int i = 0; i < 16; i++)
{
if (fields[i] == 0)
{
break;
}
size ++;
}
for (int i = 31; i > 15; i--)
{
if (fields[i] == 0)
{
break;
}
size ++;
}
return size;
}
/** Hat eine Farbe nur noch ihren König? **/
inline const bool kingOnly ()
{
return fields [1] == 0 || fields [30] == 0;
}
/** anzahl der weiße Figuren in Position **/
inline const int whiteSize ()
{
int size = 0;
for (int i = 0; i < 16; i++)
{
if (fields[i] == 0)
{
break;
}
size ++;
}
return size;
}
/** anzahl der schwarzen Figuren in Position **/
inline const int blackSize ()
{
int size = 0;
for (int i = 31; i > 15; i--)
{
if (fields[i] == 0)
{
break;
}
size ++;
}
return size;
}
inline const QList<Field> keys (Piece p)
{
QList<Field> kys;
if (colourOfPiece (p) == WHITE)
{
// weiße figuren belegen die plätze 0..15,
// schwarze sind auf 31..16
for (int i = 0; i < 16; i++)
{
if (fields [i] == 0)
{
break;
}
if (pieces [i] == p)
{
kys << fields [i];
}
}
}
else
{
for (int i = 31; i > 15; i --)
{
if (fields [i] == 0)
{
break;
}
if (pieces [i] == p)
{
kys << fields [i];
}
}
}
return kys;
};
inline const QList<Field> keys ()
{
QList<Field> kys;
for (int i = 0; i < 16; i++)
{
if (fields [i] == 0)
{
break;
}
kys << fields [i];
}
for (int i = 31; i > 15; i --)
{
if (fields [i] == 0)
{
break;
}
kys << fields [i];
}
return kys;
};
inline const Field key (Piece p)
{
if (colourOfPiece (p) == WHITE)
{
for (int i = 0; i < 16; i ++)
{
if (fields [i] == 0)
{
break;
}
if (p == pieces [i])
{
return fields [i];
}
}
return 0;
}
else
{
for (int i = 31; i > 15; i --)
{
if (fields [i] == 0)
{
break;
}
if (p == pieces [i])
{
return fields [i];
}
}
return 0;
}
return 0;
};
inline const bool contains (Field f)
{
for (int i = 0; i < 16; i++)
{
if (fields [i] == 0)
{
break;
}
else if (fields [i] == f)
{
return true;
}
}
for (int i = 31; i > 15; i --)
{
if (fields [i] == 0)
{
break;
}
else if (fields [i] == f)
{
return true;
}
}
return false;
};
inline const bool contains (Piece p)
{
if (colourOfPiece (p) == WHITE)
{
for (int i = 0; i < 16; i ++)
{
if (fields [i] == 0)
{
break;
}
if (p == pieces [i])
{
return true;
}
}
return false;
}
else
{
for (int i = 31; i > 15; i --)
{
if (fields [i] == 0)
{
break;
}
if (p == pieces [i])
{
return true;
}
}
return false;
}
return false;
};
inline const Piece value (Field f)
{
for (int i = 0; i < 16; i++)
{
if (fields [i] == 0)
{
break;
}
else if (fields [i] == f)
{
return pieces [i];
}
}
for (int i = 31; i > 15; i --)
{
if (fields [i] == 0)
{
break;
}
else if (fields [i] == f)
{
return pieces [i];
}
}
return EMPTY;
};
inline const QList<Piece> values ()
{
QList<Piece> vals;
for (int i = 0; i < 16; i++)
{
if (fields [i] == 0)
{
break;
}
vals << pieces [i];
}
for (int i = 31; i > 15; i --)
{
if (fields [i] == 0)
{
break;
}
vals << pieces [i];
}
return vals;
};
inline const Piece operator[] (Field f)
{
for (int i = 0; i < 16; i++)
{
if (fields [i] == 0)
{
break;
}
else if (fields [i] == f)
{
return pieces [i];
}
}
for (int i = 31; i > 15; i --)
{
if (fields [i] == 0)
{
break;
}
else if (fields [i] == f)
{
return pieces [i];
}
}
return EMPTY;
};
/**
* @brief Einfügen einer neuen Figur auf dem Brett.
* @details Vorsicht beim einfügen von Figuren auf Felder, auf denen schon eine Figur steht.
* da nur das halbe Array durchlaufen wird, entstehen beim schlagen Stellungen mit mehreren Figuren
* auf einem Feld wenn man die geschlagene Figur nicht von Hand löscht.
**/
inline void insert (Field f, Piece p)
{
// vor einfügen muss dafür gesorgt werden, dass feld das feld auch wirklich frei ist.
//remove (f);
if (colourOfPiece (p) == WHITE)
{
for (int i = 0; i < 16; i++)
{
if (fields[i] == 0)
{
fields [i] = f;
pieces [i] = p;
if (i<15)
{
fields [i+1] = 0;
}
break;
}
}
}
else
{
for (int i = 31; i > 15; i --)
{
if (fields[i] == 0)
{
fields [i] = f;
pieces [i] = p;
if (i>16)
{
fields [i-1] = 0;
}
break;
}
}
}
};
};
inline bool operator== (Position p1, Position p2)
{
if (p1.size () != p2.size ())
{
return false;
}
for (int i = 0; i < 16; i++)
{
if (p1.fields [i] == 0)
{
break;
}
else
{
for (int j = 0; j < 16; j++)
{
if (p2.fields [j] == 0)
{
return false;
}
else if (p1.fields [i] == p2.fields [j])
{
break;
}
}
}
}
for (int i = 31; i > 15; i --)
{
if (p1.fields [i] == 0)
{
break;
}
else
{
for (int j = 31; j > 15; j--)
{
if (p2.fields [j] == 0)
{
return false;
}
else if (p1.fields [i] == p2.fields [j])
{
break;
}
}
}
}
return true;
};
class Move;
class Move {
public:
Move () : from (00101010), by (0030303), scale (0)
{
};
Move (Field from, MoveVector by, int scale) : from (from), by (by), scale (scale)
{
};
Field from;
MoveVector by;
int scale;
//friend bool operator== (Move m, Move n);
};
inline bool operator== (Move m, Move n)
{
return m.from == n.from && m.by == n.by && m.scale == n.scale;
};
inline int qHash (Move m)
{
// from und by verwenden nur die bits 0..2, 6..8, 12..14 alle anderen sind 0
// durch shiften von by um 3 nach links lässt sich by in die lücken pressen.
// scale füllt den rest nach oben aus.
return qHash (m.from + ((m.by) << 3) + ((m.scale) << 21));
};
/**
* @name Verschiedene Zugvektoren von Figuren. Dame und König lassen sich aus Läufer+Turm zusammensetzen.
**/
/** @{ **/
const MoveVector BishopVectors [6] = {
0030202, // runter, links
0020302, // links, nach hinten
0020203, // runter, nach hinten
0030402, // hoch, links
0020304, // rechts, nach hinten
0020403 // hoch, nach hinten
};
const MoveVector WhitePawnCaptureVectors [4] = {
// 0030202, // runter, links
0020302, // links, nach hinten
0020203, // runter, nach hinten
// 0030402, // hoch, links
0020304, // rechts, nach hinten
0020403 // hoch, nach hinten
};
const MoveVector BlackPawnCaptureVectors [4] = {
// 0030202, // runter, links
0040302, // links, nach vorne
0040203, // runter, nach vorne
// 0030402, // hoch, links
0040304, // rechts, nach vorne
0040403 // hoch, nach vorne
};
const MoveVector RookVectors [3] = {
0030304,
0030403,
0040303
};
const MoveVector KnightVectors [24] = {
0050403,
0040503,
0020503,
0040103,
0020103,
0010403,
0050203,
0010203,
0050304,
0040305,
0020305,
0040301,
0020301,
0010304,
0050302,
0010302,
0030504,
0030405,
0030205,
0030401,
0030201,
0030104,
0030502,
0030102
};
/** @} **/
#endif