Add comments
This commit is contained in:
parent
64fa8ce59f
commit
08c264a9b6
BIN
media/pawn.3ds
BIN
media/pawn.3ds
Binary file not shown.
BIN
media/pawn.blend
BIN
media/pawn.blend
Binary file not shown.
21
src/ai.cpp
21
src/ai.cpp
@ -29,6 +29,10 @@ namespace toruschess {
|
||||
static const int NOMOVE = -MAXVAL - 1;
|
||||
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) {
|
||||
if (depth == 0) return curp * bal;
|
||||
|
||||
@ -72,21 +76,4 @@ namespace toruschess {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
8
src/ai.h
8
src/ai.h
@ -26,10 +26,14 @@
|
||||
@author Stefan Bühler <stbuehler@web.de>
|
||||
*/
|
||||
namespace toruschess {
|
||||
class ai{
|
||||
class ai {
|
||||
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(const Game *game);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -31,12 +31,14 @@
|
||||
*/
|
||||
namespace toruschess {
|
||||
|
||||
/** Widget for the 2d field view (Game* is shared with other widgets) */
|
||||
class Field2D : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Field2D(Game *game, QWidget *parent = 0);
|
||||
virtual ~Field2D();
|
||||
|
||||
/** Mark the destination fields */
|
||||
void markMoves(const QList<Move> &moves);
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
@ -48,12 +50,16 @@ namespace toruschess {
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event);
|
||||
virtual void wheelEvent(QWheelEvent *event);
|
||||
|
||||
/* update field buffer size */
|
||||
void checkSizes();
|
||||
/* update field buffer */
|
||||
void updateFieldBuffer();
|
||||
|
||||
/* find position on board from window coords */
|
||||
Pos findPos(int x, int y);
|
||||
|
||||
protected slots:
|
||||
/* slot for game updated event */
|
||||
void fieldUpdated();
|
||||
|
||||
private:
|
||||
@ -63,7 +69,7 @@ namespace toruschess {
|
||||
QList<Move> m_markedMoves;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -27,8 +27,6 @@
|
||||
|
||||
#include <QGLPixelBuffer>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
template<typename T>
|
||||
@ -55,13 +53,11 @@ namespace toruschess {
|
||||
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_pickTextureID(0) {
|
||||
qDebug("Field3d::Field3D");
|
||||
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);
|
||||
}
|
||||
|
||||
Field3D::~Field3D() {
|
||||
qDebug("Field3d::~Field3D");
|
||||
freeTexture();
|
||||
|
||||
if (m_skySphere) gluDeleteQuadric(m_skySphere);
|
||||
@ -83,21 +79,23 @@ namespace toruschess {
|
||||
void Field3D::initializeGL() {
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
// glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
glDisable(GL_LIGHT1);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
{
|
||||
const GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 },
|
||||
inv[] = { 0.0, 0.0, 0.0, 0.0 };
|
||||
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);
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, white);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, inv);
|
||||
glLightfv(GL_LIGHT1, GL_AMBIENT, inv);
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, white);
|
||||
}
|
||||
|
||||
glFogi(GL_FOG_MODE, GL_EXP2);
|
||||
@ -127,8 +125,8 @@ namespace toruschess {
|
||||
void Field3D::paintGL() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
// m_lib->paint_pawn();
|
||||
// return;
|
||||
glEnable(GL_LIGHT0);
|
||||
glDisable(GL_LIGHT1);
|
||||
|
||||
if (m_boardMode == TORUS) {
|
||||
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);
|
||||
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);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
@ -235,7 +256,6 @@ namespace toruschess {
|
||||
unsigned char pxbuf[3];
|
||||
glReadPixels(mx, height() - 1 - my, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pxbuf);
|
||||
paintGL();
|
||||
qDebug() << pxbuf[0] << pxbuf[1];
|
||||
p = Pos(pxbuf[0] - 50, pxbuf[1] - 50);
|
||||
return pxbuf[0] >= 50;
|
||||
}
|
||||
@ -256,9 +276,7 @@ namespace toruschess {
|
||||
|
||||
void Field3D::createTexture() {
|
||||
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_textureID = m_textureBuffer->generateDynamicTexture();
|
||||
|
||||
updateTexture();
|
||||
|
||||
@ -305,13 +323,12 @@ namespace toruschess {
|
||||
m_textureID = 0;
|
||||
}
|
||||
if (m_textureBuffer) {
|
||||
// delete m_textureBuffer;
|
||||
delete m_textureBuffer;
|
||||
m_textureBuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Field3D::updateTexture() {
|
||||
// m_textureBuffer->fill(Qt::black);
|
||||
QPainter pt(m_textureBuffer);
|
||||
pt.fillRect(QRect(0, 0, m_textureSize, m_textureSize), Qt::black);
|
||||
|
||||
@ -334,7 +351,6 @@ namespace toruschess {
|
||||
pt.setCompositionMode(QPainter::CompositionMode_Plus);
|
||||
pt.fillRect(0, 0, m_textureSize, m_textureSize, Qt::black);
|
||||
pt.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
// m_textureBuffer->updateDynamicTexture(m_textureID);
|
||||
if (m_textureID) deleteTexture(m_textureID);
|
||||
m_textureID = bindTexture(*m_textureBuffer);
|
||||
}
|
||||
|
@ -31,6 +31,9 @@
|
||||
*/
|
||||
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 {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -42,6 +45,7 @@ namespace toruschess {
|
||||
|
||||
void markMoves(const QList<Move> &moves);
|
||||
|
||||
/** Mark the destination fields */
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
BoardMode boardMode() const { return m_boardMode; }
|
||||
@ -63,15 +67,20 @@ namespace toruschess {
|
||||
virtual void timerEvent(QTimerEvent *event);
|
||||
|
||||
protected slots:
|
||||
/* slot for game updated event */
|
||||
void fieldUpdated();
|
||||
|
||||
private:
|
||||
/* update the GL_MODELVIEW matrix */
|
||||
void updateCam();
|
||||
|
||||
/* create textures: board texture, pick texture, skybox (sphere) texture */
|
||||
void createTexture();
|
||||
void freeTexture();
|
||||
/* update board texture */
|
||||
void updateTexture();
|
||||
|
||||
/* find position on board from window coords */
|
||||
bool findPos(int mx, int my, Pos &p);
|
||||
|
||||
Game *m_game;
|
||||
|
@ -26,6 +26,7 @@ namespace toruschess {
|
||||
: QDialog(parent), m_game(game) {
|
||||
m_curMode = m_game->gameMode();
|
||||
m_curAIStrength = m_game->aiStrength();
|
||||
m_curViewMode = VIEW_2D;
|
||||
setupUi(this);
|
||||
|
||||
m_bgMode = new QButtonGroup(this);
|
||||
@ -34,6 +35,11 @@ namespace toruschess {
|
||||
m_bgMode->addButton(rb_mode3, COMPUTER_HUMAN);
|
||||
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();
|
||||
|
||||
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() {
|
||||
sb_aiStrength->setValue(m_curAIStrength);
|
||||
m_bgMode->button(m_curMode)->setChecked(true);
|
||||
m_vMode->button(m_curViewMode)->setChecked(true);
|
||||
}
|
||||
|
||||
void OptionDlg::dlgAccept() {
|
||||
@ -76,6 +92,8 @@ namespace toruschess {
|
||||
m_game->setAiStrength(m_curAIStrength);
|
||||
m_curMode = (GameMode) m_bgMode->checkedId();
|
||||
m_game->setGameMode(m_curMode);
|
||||
m_curViewMode = (ViewMode) m_vMode->checkedId();
|
||||
emit setViewMode(m_curViewMode);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,11 +30,23 @@
|
||||
@author Stefan Bühler <stbuehler@web.de>
|
||||
*/
|
||||
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 {
|
||||
Q_OBJECT
|
||||
public:
|
||||
OptionDlg(Game *game, QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
void setViewMode(ViewMode viewMode);
|
||||
|
||||
public slots:
|
||||
void changedViewMode(ViewMode viewMode);
|
||||
|
||||
private slots:
|
||||
void gameChangedMode(GameMode mode);
|
||||
void gameChangedAIStrength(int aiStrength);
|
||||
@ -46,7 +58,9 @@ namespace toruschess {
|
||||
Game *m_game;
|
||||
GameMode m_curMode;
|
||||
int m_curAIStrength;
|
||||
ViewMode m_curViewMode;
|
||||
QButtonGroup *m_bgMode;
|
||||
QButtonGroup *m_vMode;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -116,9 +116,9 @@
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" >
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_view3" >
|
||||
<widget class="QRadioButton" name="rb_view1" >
|
||||
<property name="text" >
|
||||
<string>Torus</string>
|
||||
<string>2D</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -130,9 +130,9 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_view1" >
|
||||
<widget class="QRadioButton" name="rb_view3" >
|
||||
<property name="text" >
|
||||
<string>2D</string>
|
||||
<string>Torus</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -29,21 +29,29 @@
|
||||
*/
|
||||
namespace toruschess {
|
||||
|
||||
/** Handles texture/3ds loading from compiled-in Qt-Resource file
|
||||
*/
|
||||
class PieceLibrary : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PieceLibrary(QObject *parent);
|
||||
virtual ~PieceLibrary();
|
||||
|
||||
/* one PieceLibrary instance manages one set of images with a specific size
|
||||
*/
|
||||
QSize pieceSize() const { return QSize(m_width, m_height); }
|
||||
QSize minPieceSize() const { return QSize(20, 20); }
|
||||
void setSize(int width, int height);
|
||||
|
||||
/* just paint the 2d picture of the "place" figure */
|
||||
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;
|
||||
|
||||
/* paint background of a field into the given rect */
|
||||
void paint_board(QPainter &pt, bool darkField, const QRect &rect) const;
|
||||
|
||||
/* paint a 3d pawn */
|
||||
void paint_pawn();
|
||||
|
||||
private:
|
||||
|
@ -44,6 +44,9 @@ namespace toruschess {
|
||||
|
||||
TestGame::TestGame(QWidget *parent)
|
||||
: 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");
|
||||
|
||||
QWidget *centralWidget = new QWidget(this);
|
||||
|
@ -39,8 +39,6 @@
|
||||
*/
|
||||
namespace toruschess {
|
||||
|
||||
typedef enum { VIEW_2D, VIEW_3D, VIEW_TORUS } ViewMode;
|
||||
|
||||
class TestGame : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -30,6 +30,11 @@
|
||||
*/
|
||||
namespace toruschess {
|
||||
|
||||
/* Game logic
|
||||
*
|
||||
* "piece" and "player" are combined to "place": place = piece * player;
|
||||
*/
|
||||
|
||||
class Pos;
|
||||
class Field;
|
||||
class Game;
|
||||
@ -50,6 +55,7 @@ namespace toruschess {
|
||||
|
||||
QString state2string(GameState state);
|
||||
|
||||
/* coords for a field on the board */
|
||||
class Pos {
|
||||
public:
|
||||
Pos() : m_x(0), m_y(0) { }
|
||||
@ -66,6 +72,9 @@ namespace toruschess {
|
||||
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 {
|
||||
public:
|
||||
Move();
|
||||
@ -73,8 +82,11 @@ namespace toruschess {
|
||||
|
||||
const Pos& from() const { return m_from; }
|
||||
const Pos& to() const { return m_to; }
|
||||
/** figure which gets moved */
|
||||
int prevFrom() const { return m_prevFrom; }
|
||||
/** figure which gets beaten */
|
||||
int prevTo() const { return m_prevTo; }
|
||||
/** which player is moving (player from prevFrom()) */
|
||||
Player player() const { return m_player; }
|
||||
|
||||
bool operator==(const Move &other) const {
|
||||
@ -93,6 +105,8 @@ namespace toruschess {
|
||||
Player m_player;
|
||||
};
|
||||
|
||||
|
||||
/** the raw field: only knows which figures is where */
|
||||
class Field {
|
||||
public:
|
||||
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) { return m_places[p.y()][p.x()]; }
|
||||
|
||||
/* all valid moves for a piece */
|
||||
QList<Move> validMoves(const Pos &from) const;
|
||||
bool validMove(const Move &m) const; /* does not check for inCheck */
|
||||
bool move(const Move &m);
|
||||
bool undo(const Move &m);
|
||||
bool move(const Move &m); /* check if the move is valid */
|
||||
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;
|
||||
/* check if the king of a player is in check */
|
||||
bool inCheck(Player player) const;
|
||||
|
||||
void move_unchecked(const Move &m);
|
||||
void undo_unchecked(const Move &m);
|
||||
private:
|
||||
/* does not check for "in check" */
|
||||
QList<Move> simpleValidMoves(const Pos &from) const;
|
||||
|
||||
Pos m_wking, m_bking;
|
||||
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 {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -131,9 +154,12 @@ namespace toruschess {
|
||||
GameState state() const { return m_state; }
|
||||
QList<Move> moves() const { return m_moves; }
|
||||
|
||||
/* only valid moves will be done */
|
||||
bool move(const Move &m);
|
||||
/* restart the game */
|
||||
void restart();
|
||||
|
||||
/* all valid moves for the current player */
|
||||
QList<Move> possibleMoves() const;
|
||||
|
||||
GameMode gameMode() const { return m_gameMode; }
|
||||
@ -170,6 +196,7 @@ namespace toruschess {
|
||||
bool m_ignoreAI;
|
||||
};
|
||||
|
||||
/* Calculate the ai move in another thread so the main thread (gui) isn't blocked */
|
||||
class GameAIThread : public QThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user