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 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);
}
}

View File

@ -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);
};
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
};
}

View File

@ -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>

View File

@ -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:

View File

@ -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);

View File

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

View File

@ -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: