Add comments

This commit is contained in:
Stefan Bühler 2009-02-09 18:57:16 +01:00
parent 64fa8ce59f
commit 08c264a9b6
14 changed files with 136 additions and 46 deletions

Binary file not shown.

Binary file not shown.

View File

@ -29,6 +29,10 @@ namespace toruschess {
static const int NOMOVE = -MAXVAL - 1; static const int NOMOVE = -MAXVAL - 1;
static const int DRAWVAL = -7; static const int DRAWVAL = -7;
/* standard minimax search; saves the best move in *move if move != NULL;
* balance is the current "heuristic value" of a state (mult with curp to get the
* rating for a specifig player)
*/
static int minimax(Field &field, int bal, Player curp, unsigned int depth, Move *move) { static int minimax(Field &field, int bal, Player curp, unsigned int depth, Move *move) {
if (depth == 0) return curp * bal; if (depth == 0) return curp * bal;
@ -72,21 +76,4 @@ namespace toruschess {
return move; return move;
} }
Move ai::getMove(const Game *game) {
Player curp = NOPLAYER;
switch (game->state()) {
case TURN_WHITE:
curp = WHITE;
break;
case TURN_BLACK:
curp = BLACK;
break;
default:
return Move();
}
Field field = *game->field();
return getMove(field, curp, 2);
}
} }

View File

@ -28,8 +28,12 @@
namespace toruschess { namespace toruschess {
class ai { class ai {
public: public:
/** Modifies the field while calculating, so not thread-safe
* (just create a copy of the real field);
* curp: which players turn
* depth: how many moves to be calculated
*/
static Move getMove(Field &field, Player curp, int depth); static Move getMove(Field &field, Player curp, int depth);
static Move getMove(const Game *game);
}; };
} }

View File

@ -31,12 +31,14 @@
*/ */
namespace toruschess { namespace toruschess {
/** Widget for the 2d field view (Game* is shared with other widgets) */
class Field2D : public QWidget { class Field2D : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
Field2D(Game *game, QWidget *parent = 0); Field2D(Game *game, QWidget *parent = 0);
virtual ~Field2D(); virtual ~Field2D();
/** Mark the destination fields */
void markMoves(const QList<Move> &moves); void markMoves(const QList<Move> &moves);
virtual QSize sizeHint() const; virtual QSize sizeHint() const;
@ -48,12 +50,16 @@ namespace toruschess {
virtual void mouseReleaseEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event);
virtual void wheelEvent(QWheelEvent *event); virtual void wheelEvent(QWheelEvent *event);
/* update field buffer size */
void checkSizes(); void checkSizes();
/* update field buffer */
void updateFieldBuffer(); void updateFieldBuffer();
/* find position on board from window coords */
Pos findPos(int x, int y); Pos findPos(int x, int y);
protected slots: protected slots:
/* slot for game updated event */
void fieldUpdated(); void fieldUpdated();
private: private:
@ -63,7 +69,7 @@ namespace toruschess {
QList<Move> m_markedMoves; QList<Move> m_markedMoves;
int m_fieldWidth, m_fieldHeight; int m_fieldWidth, m_fieldHeight;
int m_originX, m_originY; int m_originX, m_originY; /* offset for moving board in window */
int m_mouseLastX, m_mouseLastY; int m_mouseLastX, m_mouseLastY;

View File

@ -27,8 +27,6 @@
#include <QGLPixelBuffer> #include <QGLPixelBuffer>
#include <QDebug>
#include <math.h> #include <math.h>
template<typename T> template<typename T>
@ -55,13 +53,11 @@ namespace toruschess {
m_originX(0), m_originY(0), m_mouseLastX(0), m_mouseLastY(0), m_originX(0), m_originY(0), m_mouseLastX(0), m_mouseLastY(0),
m_skySphere(0), m_skyTextureID(0), m_skyTimerID(0), m_skyOffset(0), m_skySphere(0), m_skyTextureID(0), m_skyTimerID(0), m_skyOffset(0),
m_pickTextureID(0) { m_pickTextureID(0) {
qDebug("Field3d::Field3D");
for (int x = 0; x < 8; x++) for (int y = 0; y < 8; y++) m_marked[x][y] = false; for (int x = 0; x < 8; x++) for (int y = 0; y < 8; y++) m_marked[x][y] = false;
m_lib->setSize(m_textureSize / 8, m_textureSize / 8); m_lib->setSize(m_textureSize / 8, m_textureSize / 8);
} }
Field3D::~Field3D() { Field3D::~Field3D() {
qDebug("Field3d::~Field3D");
freeTexture(); freeTexture();
if (m_skySphere) gluDeleteQuadric(m_skySphere); if (m_skySphere) gluDeleteQuadric(m_skySphere);
@ -83,21 +79,23 @@ namespace toruschess {
void Field3D::initializeGL() { void Field3D::initializeGL() {
glClearColor(0.0, 0.0, 0.0, 0.0); glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
// glEnable(GL_CULL_FACE);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0); glEnable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glEnable(GL_COLOR_MATERIAL); glEnable(GL_COLOR_MATERIAL);
{ {
const GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 }, const GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 },
inv[] = { 0.0, 0.0, 0.0, 0.0 }; inv[] = { 0.0, 0.0, 0.0, 0.0 };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, white); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, white);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, inv); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, inv); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, inv);
glLightfv(GL_LIGHT0, GL_AMBIENT, white); glLightfv(GL_LIGHT0, GL_AMBIENT, white);
glLightfv(GL_LIGHT0, GL_DIFFUSE, inv); glLightfv(GL_LIGHT0, GL_DIFFUSE, inv);
glLightfv(GL_LIGHT1, GL_AMBIENT, inv);
glLightfv(GL_LIGHT1, GL_DIFFUSE, white);
} }
glFogi(GL_FOG_MODE, GL_EXP2); glFogi(GL_FOG_MODE, GL_EXP2);
@ -127,8 +125,8 @@ namespace toruschess {
void Field3D::paintGL() { void Field3D::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
// m_lib->paint_pawn(); glEnable(GL_LIGHT0);
// return; glDisable(GL_LIGHT1);
if (m_boardMode == TORUS) { if (m_boardMode == TORUS) {
glDisable(GL_FOG); glDisable(GL_FOG);
@ -180,6 +178,29 @@ namespace toruschess {
glTexCoord2f( repeat+ox, -repeat+oy); glVertex3f( 10*repeat, 0, 10*repeat); glTexCoord2f( repeat+ox, -repeat+oy); glVertex3f( 10*repeat, 0, 10*repeat);
glTexCoord2f( repeat+ox, repeat+oy); glVertex3f( 10*repeat, 0, -10*repeat); glTexCoord2f( repeat+ox, repeat+oy); glVertex3f( 10*repeat, 0, -10*repeat);
glEnd(); glEnd();
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHT1);
glDisable(GL_LIGHT0);
glMatrixMode(GL_MODELVIEW);
ox *= -10.0; oy *= 10.0;
ox += 10.0/16; oy += 10.0/16;
for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) {
if (m_game->field()->piece(Pos(i, j)) == PAWN) {
if (m_game->field()->player(Pos(i, j)) == WHITE) {
glColor3f(1.0, 1.0, 1.0);
} else {
glColor3f(.0, .0, .0);
}
for (int x = -10; x <= 10; x++) for (int y = -10; y <= 10; y++) {
glPushMatrix();
glTranslatef(ox + 10.0/8.0*i + 10*x, 0, oy + 10.0/8.0*j + 10*y);
glRotatef(-90, 1, 0, 0);
m_lib->paint_pawn();
glPopMatrix();
}
}
}
} }
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
@ -235,7 +256,6 @@ namespace toruschess {
unsigned char pxbuf[3]; unsigned char pxbuf[3];
glReadPixels(mx, height() - 1 - my, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pxbuf); glReadPixels(mx, height() - 1 - my, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pxbuf);
paintGL(); paintGL();
qDebug() << pxbuf[0] << pxbuf[1];
p = Pos(pxbuf[0] - 50, pxbuf[1] - 50); p = Pos(pxbuf[0] - 50, pxbuf[1] - 50);
return pxbuf[0] >= 50; return pxbuf[0] >= 50;
} }
@ -256,9 +276,7 @@ namespace toruschess {
void Field3D::createTexture() { void Field3D::createTexture() {
freeTexture(); freeTexture();
// m_textureBuffer = new QGLPixelBuffer(QSize(m_textureSize, m_textureSize), QGLFormat::defaultFormat(), this);
m_textureBuffer = new QImage(QSize(m_textureSize, m_textureSize), QImage::Format_ARGB32_Premultiplied); m_textureBuffer = new QImage(QSize(m_textureSize, m_textureSize), QImage::Format_ARGB32_Premultiplied);
// m_textureID = m_textureBuffer->generateDynamicTexture();
updateTexture(); updateTexture();
@ -305,13 +323,12 @@ namespace toruschess {
m_textureID = 0; m_textureID = 0;
} }
if (m_textureBuffer) { if (m_textureBuffer) {
// delete m_textureBuffer; delete m_textureBuffer;
m_textureBuffer = 0; m_textureBuffer = 0;
} }
} }
void Field3D::updateTexture() { void Field3D::updateTexture() {
// m_textureBuffer->fill(Qt::black);
QPainter pt(m_textureBuffer); QPainter pt(m_textureBuffer);
pt.fillRect(QRect(0, 0, m_textureSize, m_textureSize), Qt::black); pt.fillRect(QRect(0, 0, m_textureSize, m_textureSize), Qt::black);
@ -334,7 +351,6 @@ namespace toruschess {
pt.setCompositionMode(QPainter::CompositionMode_Plus); pt.setCompositionMode(QPainter::CompositionMode_Plus);
pt.fillRect(0, 0, m_textureSize, m_textureSize, Qt::black); pt.fillRect(0, 0, m_textureSize, m_textureSize, Qt::black);
pt.setCompositionMode(QPainter::CompositionMode_SourceOver); pt.setCompositionMode(QPainter::CompositionMode_SourceOver);
// m_textureBuffer->updateDynamicTexture(m_textureID);
if (m_textureID) deleteTexture(m_textureID); if (m_textureID) deleteTexture(m_textureID);
m_textureID = bindTexture(*m_textureBuffer); m_textureID = bindTexture(*m_textureBuffer);
} }

View File

@ -31,6 +31,9 @@
*/ */
namespace toruschess { namespace toruschess {
/** Widget for the 3d field view (Game* is shared with other widgets)
* Available modes: Plane vs. Torus and 2d vs 3d Figures
*/
class Field3D : public QGLWidget { class Field3D : public QGLWidget {
Q_OBJECT Q_OBJECT
public: public:
@ -42,6 +45,7 @@ namespace toruschess {
void markMoves(const QList<Move> &moves); void markMoves(const QList<Move> &moves);
/** Mark the destination fields */
virtual QSize sizeHint() const; virtual QSize sizeHint() const;
BoardMode boardMode() const { return m_boardMode; } BoardMode boardMode() const { return m_boardMode; }
@ -63,15 +67,20 @@ namespace toruschess {
virtual void timerEvent(QTimerEvent *event); virtual void timerEvent(QTimerEvent *event);
protected slots: protected slots:
/* slot for game updated event */
void fieldUpdated(); void fieldUpdated();
private: private:
/* update the GL_MODELVIEW matrix */
void updateCam(); void updateCam();
/* create textures: board texture, pick texture, skybox (sphere) texture */
void createTexture(); void createTexture();
void freeTexture(); void freeTexture();
/* update board texture */
void updateTexture(); void updateTexture();
/* find position on board from window coords */
bool findPos(int mx, int my, Pos &p); bool findPos(int mx, int my, Pos &p);
Game *m_game; Game *m_game;

View File

@ -26,6 +26,7 @@ namespace toruschess {
: QDialog(parent), m_game(game) { : QDialog(parent), m_game(game) {
m_curMode = m_game->gameMode(); m_curMode = m_game->gameMode();
m_curAIStrength = m_game->aiStrength(); m_curAIStrength = m_game->aiStrength();
m_curViewMode = VIEW_2D;
setupUi(this); setupUi(this);
m_bgMode = new QButtonGroup(this); m_bgMode = new QButtonGroup(this);
@ -34,6 +35,11 @@ namespace toruschess {
m_bgMode->addButton(rb_mode3, COMPUTER_HUMAN); m_bgMode->addButton(rb_mode3, COMPUTER_HUMAN);
m_bgMode->addButton(rb_mode4, COMPUTER_COMPUTER); m_bgMode->addButton(rb_mode4, COMPUTER_COMPUTER);
m_vMode = new QButtonGroup(this);
m_vMode->addButton(rb_view1, VIEW_2D);
m_vMode->addButton(rb_view2, VIEW_3D);
m_vMode->addButton(rb_view3, VIEW_TORUS);
dlgReset(); dlgReset();
connect(m_game, SIGNAL(changedMode(GameMode)), this, SLOT(gameChangedMode(GameMode))); connect(m_game, SIGNAL(changedMode(GameMode)), this, SLOT(gameChangedMode(GameMode)));
@ -66,9 +72,19 @@ namespace toruschess {
} }
} }
void OptionDlg::changedViewMode(ViewMode viewMode) {
if (m_curViewMode != viewMode) {
if (m_vMode->checkedId() == m_curViewMode) {
m_vMode->button(viewMode)->setChecked(true);
}
m_curViewMode = viewMode;
}
}
void OptionDlg::dlgReset() { void OptionDlg::dlgReset() {
sb_aiStrength->setValue(m_curAIStrength); sb_aiStrength->setValue(m_curAIStrength);
m_bgMode->button(m_curMode)->setChecked(true); m_bgMode->button(m_curMode)->setChecked(true);
m_vMode->button(m_curViewMode)->setChecked(true);
} }
void OptionDlg::dlgAccept() { void OptionDlg::dlgAccept() {
@ -76,6 +92,8 @@ namespace toruschess {
m_game->setAiStrength(m_curAIStrength); m_game->setAiStrength(m_curAIStrength);
m_curMode = (GameMode) m_bgMode->checkedId(); m_curMode = (GameMode) m_bgMode->checkedId();
m_game->setGameMode(m_curMode); m_game->setGameMode(m_curMode);
m_curViewMode = (ViewMode) m_vMode->checkedId();
emit setViewMode(m_curViewMode);
} }
} }

View File

@ -30,11 +30,23 @@
@author Stefan Bühler <stbuehler@web.de> @author Stefan Bühler <stbuehler@web.de>
*/ */
namespace toruschess { namespace toruschess {
typedef enum { VIEW_2D, VIEW_3D, VIEW_TORUS } ViewMode;
/** Option Dialog
* Game options are set directly (so one dialog contols only one game instance)
* The view mode option is handled via signal/slot (default is VIEW_2D)
*/
class OptionDlg : public QDialog, private Ui::OptionDlg { class OptionDlg : public QDialog, private Ui::OptionDlg {
Q_OBJECT Q_OBJECT
public: public:
OptionDlg(Game *game, QWidget *parent = 0); OptionDlg(Game *game, QWidget *parent = 0);
signals:
void setViewMode(ViewMode viewMode);
public slots:
void changedViewMode(ViewMode viewMode);
private slots: private slots:
void gameChangedMode(GameMode mode); void gameChangedMode(GameMode mode);
void gameChangedAIStrength(int aiStrength); void gameChangedAIStrength(int aiStrength);
@ -46,7 +58,9 @@ namespace toruschess {
Game *m_game; Game *m_game;
GameMode m_curMode; GameMode m_curMode;
int m_curAIStrength; int m_curAIStrength;
ViewMode m_curViewMode;
QButtonGroup *m_bgMode; QButtonGroup *m_bgMode;
QButtonGroup *m_vMode;
}; };
} }

View File

@ -116,9 +116,9 @@
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout_2" > <layout class="QHBoxLayout" name="horizontalLayout_2" >
<item> <item>
<widget class="QRadioButton" name="rb_view3" > <widget class="QRadioButton" name="rb_view1" >
<property name="text" > <property name="text" >
<string>Torus</string> <string>2D</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -130,9 +130,9 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QRadioButton" name="rb_view1" > <widget class="QRadioButton" name="rb_view3" >
<property name="text" > <property name="text" >
<string>2D</string> <string>Torus</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -29,21 +29,29 @@
*/ */
namespace toruschess { namespace toruschess {
/** Handles texture/3ds loading from compiled-in Qt-Resource file
*/
class PieceLibrary : public QObject { class PieceLibrary : public QObject {
Q_OBJECT Q_OBJECT
public: public:
PieceLibrary(QObject *parent); PieceLibrary(QObject *parent);
virtual ~PieceLibrary(); virtual ~PieceLibrary();
/* one PieceLibrary instance manages one set of images with a specific size
*/
QSize pieceSize() const { return QSize(m_width, m_height); } QSize pieceSize() const { return QSize(m_width, m_height); }
QSize minPieceSize() const { return QSize(20, 20); } QSize minPieceSize() const { return QSize(20, 20); }
void setSize(int width, int height); void setSize(int width, int height);
/* just paint the 2d picture of the "place" figure */
void paint(QPainter &pt, int place) const; void paint(QPainter &pt, int place) const;
/* just paint the 2d picture of the "place" figure into the given rect */
void paint(QPainter &pt, int place, const QRect &rect) const; void paint(QPainter &pt, int place, const QRect &rect) const;
/* paint background of a field into the given rect */
void paint_board(QPainter &pt, bool darkField, const QRect &rect) const; void paint_board(QPainter &pt, bool darkField, const QRect &rect) const;
/* paint a 3d pawn */
void paint_pawn(); void paint_pawn();
private: private:

View File

@ -44,6 +44,9 @@ namespace toruschess {
TestGame::TestGame(QWidget *parent) TestGame::TestGame(QWidget *parent)
: QMainWindow(parent), m_game(new Game()), m_optionDlg(new OptionDlg(m_game, this)), m_viewMode((ViewMode) -1) { : QMainWindow(parent), m_game(new Game()), m_optionDlg(new OptionDlg(m_game, this)), m_viewMode((ViewMode) -1) {
connect(this, SIGNAL(changedViewMode(ViewMode)), m_optionDlg, SLOT(changedViewMode(ViewMode)));
connect(m_optionDlg, SIGNAL(setViewMode(ViewMode)), this, SLOT(setViewMode(ViewMode)));
setWindowTitle("Torus Chess"); setWindowTitle("Torus Chess");
QWidget *centralWidget = new QWidget(this); QWidget *centralWidget = new QWidget(this);

View File

@ -39,8 +39,6 @@
*/ */
namespace toruschess { namespace toruschess {
typedef enum { VIEW_2D, VIEW_3D, VIEW_TORUS } ViewMode;
class TestGame : public QMainWindow { class TestGame : public QMainWindow {
Q_OBJECT Q_OBJECT
public: public:

View File

@ -30,6 +30,11 @@
*/ */
namespace toruschess { namespace toruschess {
/* Game logic
*
* "piece" and "player" are combined to "place": place = piece * player;
*/
class Pos; class Pos;
class Field; class Field;
class Game; class Game;
@ -50,6 +55,7 @@ namespace toruschess {
QString state2string(GameState state); QString state2string(GameState state);
/* coords for a field on the board */
class Pos { class Pos {
public: public:
Pos() : m_x(0), m_y(0) { } Pos() : m_x(0), m_y(0) { }
@ -66,6 +72,9 @@ namespace toruschess {
int m_x, m_y; int m_x, m_y;
}; };
/* some basic information for one move: from and to,
* which figure got moved, which (if any) got beaten
*/
class Move { class Move {
public: public:
Move(); Move();
@ -73,8 +82,11 @@ namespace toruschess {
const Pos& from() const { return m_from; } const Pos& from() const { return m_from; }
const Pos& to() const { return m_to; } const Pos& to() const { return m_to; }
/** figure which gets moved */
int prevFrom() const { return m_prevFrom; } int prevFrom() const { return m_prevFrom; }
/** figure which gets beaten */
int prevTo() const { return m_prevTo; } int prevTo() const { return m_prevTo; }
/** which player is moving (player from prevFrom()) */
Player player() const { return m_player; } Player player() const { return m_player; }
bool operator==(const Move &other) const { bool operator==(const Move &other) const {
@ -93,6 +105,8 @@ namespace toruschess {
Player m_player; Player m_player;
}; };
/** the raw field: only knows which figures is where */
class Field { class Field {
public: public:
Field(); Field();
@ -104,23 +118,32 @@ namespace toruschess {
int place(const Pos &p) const { return m_places[p.y()][p.x()]; } int place(const Pos &p) const { return m_places[p.y()][p.x()]; }
int& place(const Pos &p) { return m_places[p.y()][p.x()]; } int& place(const Pos &p) { return m_places[p.y()][p.x()]; }
/* all valid moves for a piece */
QList<Move> validMoves(const Pos &from) const; QList<Move> validMoves(const Pos &from) const;
bool validMove(const Move &m) const; /* does not check for inCheck */ bool validMove(const Move &m) const; /* does not check for inCheck */
bool move(const Move &m); bool move(const Move &m); /* check if the move is valid */
bool undo(const Move &m); bool undo(const Move &m); /* check if the undo is valid */
/* check if the king of a player at pos pking is in check */
bool inCheck(Player player, const Pos &pking) const; bool inCheck(Player player, const Pos &pking) const;
/* check if the king of a player is in check */
bool inCheck(Player player) const; bool inCheck(Player player) const;
void move_unchecked(const Move &m); void move_unchecked(const Move &m);
void undo_unchecked(const Move &m); void undo_unchecked(const Move &m);
private: private:
/* does not check for "in check" */
QList<Move> simpleValidMoves(const Pos &from) const; QList<Move> simpleValidMoves(const Pos &from) const;
Pos m_wking, m_bking; Pos m_wking, m_bking;
int m_places[8][8]; int m_places[8][8];
}; };
/* contains a field plus addition information about the game state
* such as which turn it is or who has won
* also is responsible to do the ai moves, if activated
*/
class Game : public QObject { class Game : public QObject {
Q_OBJECT Q_OBJECT
public: public:
@ -131,9 +154,12 @@ namespace toruschess {
GameState state() const { return m_state; } GameState state() const { return m_state; }
QList<Move> moves() const { return m_moves; } QList<Move> moves() const { return m_moves; }
/* only valid moves will be done */
bool move(const Move &m); bool move(const Move &m);
/* restart the game */
void restart(); void restart();
/* all valid moves for the current player */
QList<Move> possibleMoves() const; QList<Move> possibleMoves() const;
GameMode gameMode() const { return m_gameMode; } GameMode gameMode() const { return m_gameMode; }
@ -170,6 +196,7 @@ namespace toruschess {
bool m_ignoreAI; bool m_ignoreAI;
}; };
/* Calculate the ai move in another thread so the main thread (gui) isn't blocked */
class GameAIThread : public QThread { class GameAIThread : public QThread {
Q_OBJECT Q_OBJECT
public: public: