|
|
|
/* Yo Emacs, this is -*- C++ -*-
|
|
|
|
*******************************************************************
|
|
|
|
*******************************************************************
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* KREVERSI
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*******************************************************************
|
|
|
|
*
|
|
|
|
* A Reversi (or sometimes called Othello) game
|
|
|
|
*
|
|
|
|
*******************************************************************
|
|
|
|
*
|
|
|
|
* created 1997 by Mario Weilguni <mweilguni@sime.com>
|
|
|
|
*
|
|
|
|
*******************************************************************
|
|
|
|
*
|
|
|
|
* This file is part of the KDE project "KREVERSI"
|
|
|
|
*
|
|
|
|
* KREVERSI 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, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* KREVERSI 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 KREVERSI; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*******************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqlistbox.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kstatusbar.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <kstdgameaction.h>
|
|
|
|
#include <kkeydialog.h>
|
|
|
|
#include <kconfigdialog.h>
|
|
|
|
#include <knotifyclient.h>
|
|
|
|
#include <knotifydialog.h>
|
|
|
|
#include <kexthighscore.h>
|
|
|
|
|
|
|
|
#include "Score.h"
|
|
|
|
#include "kreversi.h"
|
|
|
|
|
|
|
|
// Automatically generated headers
|
|
|
|
#include "prefs.h"
|
|
|
|
#include "settings.h"
|
|
|
|
|
|
|
|
#include "kreversi.moc"
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
// class KReversi
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef PICDATA
|
|
|
|
#define PICDATA(x) \
|
|
|
|
KGlobal::dirs()->findResource("appdata", TQString("pics/") + x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
KReversi::KReversi()
|
|
|
|
: KZoomMainWindow(10, 300, 5, "kreversi"),
|
|
|
|
m_gameOver(false)
|
|
|
|
{
|
|
|
|
TQWidget *w;
|
|
|
|
TQGridLayout *top;
|
|
|
|
|
|
|
|
KNotifyClient::startDaemon();
|
|
|
|
|
|
|
|
// The game.
|
|
|
|
m_game = new QReversiGame();
|
|
|
|
m_cheating = false;
|
|
|
|
m_gameOver = false;
|
|
|
|
m_humanColor = Black;
|
|
|
|
|
|
|
|
// The Engine
|
|
|
|
m_engine = new Engine();
|
|
|
|
setStrength(1);
|
|
|
|
|
|
|
|
// The visual stuff
|
|
|
|
w = new TQWidget(this);
|
|
|
|
setCentralWidget(w);
|
|
|
|
|
|
|
|
top = new TQGridLayout(w, 2, 2);
|
|
|
|
|
|
|
|
// The reversi game view.
|
|
|
|
m_gameView = new QReversiGameView(w, m_game);
|
|
|
|
top->addMultiCellWidget(m_gameView, 0, 1, 0, 0);
|
|
|
|
|
|
|
|
// Populate the GUI.
|
|
|
|
createKActions();
|
|
|
|
addWidget(m_gameView);
|
|
|
|
|
|
|
|
// Connect the signals from the game with slots of the view
|
|
|
|
//
|
|
|
|
// The only part of the view that is left in this class is the
|
|
|
|
// indicator of whose turn it is in the status bar. The rest is
|
|
|
|
// in the game view.
|
|
|
|
connect(m_game, TQT_SIGNAL(sig_newGame()), TQT_TQOBJECT(this), TQT_SLOT(showTurn()));
|
|
|
|
connect(m_game, TQT_SIGNAL(sig_move(uint, Move&)),
|
|
|
|
TQT_TQOBJECT(this), TQT_SLOT(handleMove(uint, Move&))); // Calls showTurn().
|
|
|
|
connect(m_game, TQT_SIGNAL(sig_update()), TQT_TQOBJECT(this), TQT_SLOT(showTurn()));
|
|
|
|
connect(m_game, TQT_SIGNAL(sig_gameOver()), TQT_TQOBJECT(this), TQT_SLOT(slotGameOver()));
|
|
|
|
|
|
|
|
// Signal that is sent when the user clicks on the board.
|
|
|
|
connect(m_gameView, TQT_SIGNAL(signalSquareClicked(int, int)),
|
|
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotSquareClicked(int, int)));
|
|
|
|
|
|
|
|
loadSettings();
|
|
|
|
|
|
|
|
setupGUI();
|
|
|
|
init("popup");
|
|
|
|
m_gameView->start();
|
|
|
|
|
|
|
|
slotNewGame();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KReversi::~KReversi()
|
|
|
|
{
|
|
|
|
delete m_game;
|
|
|
|
delete m_engine;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create all KActions used in KReversi.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::createKActions()
|
|
|
|
{
|
|
|
|
// Standard Game Actions.
|
|
|
|
KStdGameAction::gameNew(TQT_TQOBJECT(this), TQT_SLOT(slotNewGame()), actionCollection(),
|
|
|
|
"game_new");
|
|
|
|
KStdGameAction::load(TQT_TQOBJECT(this), TQT_SLOT(slotOpenGame()), actionCollection());
|
|
|
|
KStdGameAction::save(TQT_TQOBJECT(this), TQT_SLOT(slotSave()), actionCollection());
|
|
|
|
KStdGameAction::quit(TQT_TQOBJECT(this), TQT_SLOT(close()), actionCollection());
|
|
|
|
KStdGameAction::hint(TQT_TQOBJECT(this), TQT_SLOT(slotHint()), actionCollection(),
|
|
|
|
"game_hint");
|
|
|
|
KStdGameAction::undo(TQT_TQOBJECT(this), TQT_SLOT(slotUndo()), actionCollection(),
|
|
|
|
"game_undo");
|
|
|
|
|
|
|
|
// Non-standard Game Actions: Stop, Continue, Switch sides
|
|
|
|
stopAction = new KAction(i18n("&Stop Thinking"), "game_stop", TQt::Key_Escape,
|
|
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotInterrupt()), actionCollection(),
|
|
|
|
"game_stop");
|
|
|
|
continueAction = new KAction(i18n("&Continue Thinking"), "reload", 0,
|
|
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotContinue()), actionCollection(),
|
|
|
|
"game_continue");
|
|
|
|
new KAction(i18n("S&witch Sides"), 0, 0,
|
|
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotSwitchSides()), actionCollection(),
|
|
|
|
"game_switch_sides");
|
|
|
|
|
|
|
|
// Some more standard game actions: Highscores, Settings.
|
|
|
|
KStdGameAction::highscores(TQT_TQOBJECT(this), TQT_SLOT(showHighScoreDialog()), actionCollection());
|
|
|
|
KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT(slotEditSettings()), actionCollection());
|
|
|
|
|
|
|
|
// Actions for the view(s).
|
|
|
|
showLastMoveAction = new KToggleAction(i18n("Show Last Move"), "lastmoves", 0,
|
|
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotShowLastMove()),
|
|
|
|
actionCollection(),
|
|
|
|
"show_last_move");
|
|
|
|
showLegalMovesAction = new KToggleAction(i18n("Show Legal Moves"), "legalmoves", 0,
|
|
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotShowLegalMoves()),
|
|
|
|
actionCollection(),
|
|
|
|
"show_legal_moves");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// Methods for the engine
|
|
|
|
|
|
|
|
|
|
|
|
// Set the strength for the engine. We keep track of the lowest
|
|
|
|
// strength that was used during a game and if the user wins, this is
|
|
|
|
// the strength that we will store in the highscore file.
|
|
|
|
|
|
|
|
void KReversi::setStrength(uint strength)
|
|
|
|
{
|
|
|
|
// FIXME: 7 should be MAXSTRENGTH or something similar.
|
|
|
|
Q_ASSERT( 1 <= strength && strength <= 7 );
|
|
|
|
|
|
|
|
strength = TQMAX(TQMIN(strength, 7), 1);
|
|
|
|
m_engine->setStrength(strength);
|
|
|
|
if (m_lowestStrength < strength)
|
|
|
|
m_lowestStrength = strength;
|
|
|
|
KExtHighscore::setGameType(m_lowestStrength-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// Slots for KActions
|
|
|
|
|
|
|
|
|
|
|
|
// A slot that is called when the user wants a new game.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::slotNewGame()
|
|
|
|
{
|
|
|
|
// If already playing, ask the player if he wants to abort the old game.
|
|
|
|
if ( isPlaying() ) {
|
|
|
|
if (KMessageBox
|
|
|
|
::warningYesNo(0,
|
|
|
|
i18n("You are already running an unfinished game. "
|
|
|
|
"If you abort the old game to start a new one, "
|
|
|
|
"the old game will be registered as a loss in "
|
|
|
|
"the highscore file.\n"
|
|
|
|
"What do you want to do?"),
|
|
|
|
i18n("Abort Current Game?"),
|
|
|
|
i18n("Abort Old Game"),
|
|
|
|
i18n("Continue Old Game")) == KMessageBox::No)
|
|
|
|
return;
|
|
|
|
|
|
|
|
KExtHighscore::submitScore(KExtHighscore::Lost, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_gameOver = false;
|
|
|
|
m_cheating = false;
|
|
|
|
|
|
|
|
m_game->newGame();
|
|
|
|
m_competitiveGame = Prefs::competitiveGameChoice();
|
|
|
|
m_lowestStrength = strength();
|
|
|
|
//kdDebug() << "Competitive: " << m_competitiveGame << endl;
|
|
|
|
|
|
|
|
// Set the state to waiting for the humans move.
|
|
|
|
setState(Ready);
|
|
|
|
|
|
|
|
// Black always makes first move.
|
|
|
|
if (m_humanColor == White)
|
|
|
|
computerMakeMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Open an earlier saved game from the config file.
|
|
|
|
//
|
|
|
|
// FIXME: Should give a choice to load from an ordinary file (SGF?)
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::slotOpenGame()
|
|
|
|
{
|
|
|
|
KConfig *config = kapp->config();
|
|
|
|
config->setGroup("Savegame");
|
|
|
|
|
|
|
|
if (loadGame(config))
|
|
|
|
Prefs::setSkill(m_engine->strength());
|
|
|
|
m_gameView->setHumanColor(humanColor());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Save a game to the config file.
|
|
|
|
//
|
|
|
|
// FIXME: Should give a choice to save as an ordinary file (SGF?)
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::slotSave()
|
|
|
|
{
|
|
|
|
KConfig *config = kapp->config();
|
|
|
|
config->setGroup("Savegame");
|
|
|
|
saveGame(config);
|
|
|
|
|
|
|
|
KMessageBox::information(this, i18n("Game saved."));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::slotHint()
|
|
|
|
{
|
|
|
|
Move move;
|
|
|
|
|
|
|
|
if (state() != Ready)
|
|
|
|
return;
|
|
|
|
|
|
|
|
setState(Thinking);
|
|
|
|
move = m_engine->computeMove(m_game, m_competitiveGame);
|
|
|
|
|
|
|
|
setState(Hint);
|
|
|
|
m_gameView->showHint(move);
|
|
|
|
|
|
|
|
setState(Ready);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Takes back last set of moves
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::slotUndo()
|
|
|
|
{
|
|
|
|
if (state() != Ready)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Can't undo anything if no moves are made.
|
|
|
|
if (m_game->moveNumber() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Undo all moves of the same color as the last one.
|
|
|
|
Color last_color = m_game->lastMove().color();
|
|
|
|
while (m_game->moveNumber() != 0
|
|
|
|
&& last_color == m_game->lastMove().color()) {
|
|
|
|
m_game->undoMove();
|
|
|
|
m_gameView->removeMove(m_game->moveNumber());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Take back one more move.
|
|
|
|
if (m_game->moveNumber() > 0) {
|
|
|
|
m_game->undoMove();
|
|
|
|
m_gameView->removeMove(m_game->moveNumber());
|
|
|
|
|
|
|
|
// FIXME: Call some method in m_gameView.
|
|
|
|
m_gameView->setCurrentMove(m_game->moveNumber() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_game->toMove() == computerColor()) {
|
|
|
|
// Must tqrepaint so that the new move is not shown before the old
|
|
|
|
// one is removed on the screen.
|
|
|
|
m_gameView->tqrepaint();
|
|
|
|
computerMakeMove();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_gameView->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Interrupt thinking of game engine.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::slotInterrupt()
|
|
|
|
{
|
|
|
|
m_engine->setInterrupt(TRUE);
|
|
|
|
|
|
|
|
// Indicate that the computer was interrupted.
|
|
|
|
showTurn();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Continues a move if it was interrupted earlier.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::slotContinue()
|
|
|
|
{
|
|
|
|
if (interrupted())
|
|
|
|
computerMakeMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Turn on or off showing of legal moves in the board view.
|
|
|
|
|
|
|
|
void KReversi::slotShowLastMove()
|
|
|
|
{
|
|
|
|
m_gameView->setShowLastMove(showLastMoveAction->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Turn on or off showing of legal moves in the board view.
|
|
|
|
|
|
|
|
void KReversi::slotShowLegalMoves()
|
|
|
|
{
|
|
|
|
m_gameView->setShowLegalMoves(showLegalMovesAction->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::slotSwitchSides()
|
|
|
|
{
|
|
|
|
if (state() != Ready)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (interrupted()) {
|
|
|
|
KMessageBox::information(this, i18n("You cannot switch sides in the middle of the computer's move."),
|
|
|
|
i18n("Notice"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// It's ok to change sides before the first move.
|
|
|
|
if (m_game->moveNumber() != 0) {
|
|
|
|
int res = KMessageBox::warningContinueCancel(this,
|
|
|
|
i18n("If you switch side, your score will not be added to the highscores."),
|
|
|
|
TQString(), TQString(), "switch_side_warning");
|
|
|
|
if ( res==KMessageBox::Cancel )
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_cheating = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_humanColor = opponent(m_humanColor);
|
|
|
|
|
|
|
|
// Update the human color in the window.
|
|
|
|
m_gameView->setHumanColor(m_humanColor);
|
|
|
|
|
|
|
|
kapp->processEvents();
|
|
|
|
computerMakeMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// Slots for the game IO
|
|
|
|
|
|
|
|
|
|
|
|
// Handle mouse clicks.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::slotSquareClicked(int row, int col)
|
|
|
|
{
|
|
|
|
// Can't move when it is the computers turn.
|
|
|
|
if ( interrupted() ) {
|
|
|
|
illegalMove();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state() == Ready)
|
|
|
|
humanMakeMove(row, col);
|
|
|
|
else if (state() == Hint) {
|
|
|
|
m_gameView->quitHint();
|
|
|
|
setState(Ready);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
illegalMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// Slots for the game view
|
|
|
|
|
|
|
|
|
|
|
|
// Show the move in the move view.
|
|
|
|
// FIXME: Move this to the gameview.
|
|
|
|
|
|
|
|
void KReversi::handleMove(uint /*moveno*/, Move& /*move*/)
|
|
|
|
{
|
|
|
|
showTurn();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// A slot that is called when it is time to show whose turn it is.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::showTurn()
|
|
|
|
{
|
|
|
|
showTurn(m_game->toMove());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KReversi::showTurn(Color color)
|
|
|
|
{
|
|
|
|
// If we are not playing, do nothing.
|
|
|
|
if (m_gameOver)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (color == humanColor())
|
|
|
|
statusBar()->message(i18n("Your turn"));
|
|
|
|
else if (color == computerColor()) {
|
|
|
|
TQString message = i18n("Computer's turn");
|
|
|
|
|
|
|
|
// We can't use the interrupted() test here since we might be in a
|
|
|
|
// middle state when called from slotInterrupt().
|
|
|
|
if (m_state == Thinking)
|
|
|
|
message += i18n(" (interrupted)");
|
|
|
|
statusBar()->message(message);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
statusBar()->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// A slot that is called when the game ends.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::slotGameOver()
|
|
|
|
{
|
|
|
|
uint black = m_game->score(Black);
|
|
|
|
uint white = m_game->score(White);
|
|
|
|
|
|
|
|
setState(Ready);
|
|
|
|
|
|
|
|
if (black > white)
|
|
|
|
showGameOver(Black);
|
|
|
|
else if (black < white)
|
|
|
|
showGameOver(White);
|
|
|
|
else
|
|
|
|
showGameOver(Nobody);
|
|
|
|
|
|
|
|
showTurn(Nobody);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// Private methods
|
|
|
|
|
|
|
|
|
|
|
|
// Handle the humans move.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::humanMakeMove(int row, int col)
|
|
|
|
{
|
|
|
|
if (state() != Ready)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Color color = m_game->toMove();
|
|
|
|
|
|
|
|
// Create a move from the mouse click and see if it is legal.
|
|
|
|
// If it is, then make a human move.
|
|
|
|
Move move(color, col + 1, row + 1);
|
|
|
|
if (m_game->moveIsLegal(move)) {
|
|
|
|
// Do the move. The view is automatically updated.
|
|
|
|
m_game->doMove(move);
|
|
|
|
|
|
|
|
if (!m_game->moveIsAtAllPossible()) {
|
|
|
|
setState(Ready);
|
|
|
|
slotGameOver();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (color != m_game->toMove())
|
|
|
|
computerMakeMove();
|
|
|
|
} else
|
|
|
|
illegalMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Make a computer move.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::computerMakeMove()
|
|
|
|
{
|
|
|
|
MoveList moves;
|
|
|
|
|
|
|
|
// Check if the computer can move.
|
|
|
|
Color color = m_game->toMove();
|
|
|
|
Color opponent = ::opponent(color);
|
|
|
|
|
|
|
|
if (!m_game->moveIsPossible(color))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Make computer moves until the human can play or until the game is over.
|
|
|
|
setState(Thinking);
|
|
|
|
do {
|
|
|
|
Move move;
|
|
|
|
|
|
|
|
if (!m_game->moveIsAtAllPossible()) {
|
|
|
|
setState(Ready);
|
|
|
|
slotGameOver();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
move = m_engine->computeMove(m_game, m_competitiveGame);
|
|
|
|
if (move.x() == -1) {
|
|
|
|
setState(Ready);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
usleep(300000); // Pretend we have to think hard.
|
|
|
|
|
|
|
|
// Do the move on the board. The view is automatically updated.
|
|
|
|
//playSound("click.wav");
|
|
|
|
m_game->doMove(move);
|
|
|
|
} while (!m_game->moveIsPossible(opponent));
|
|
|
|
|
|
|
|
setState(Ready);
|
|
|
|
|
|
|
|
if (!m_game->moveIsAtAllPossible()) {
|
|
|
|
slotGameOver();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Handle an attempt to make an illegal move by the human.
|
|
|
|
|
|
|
|
void KReversi::illegalMove()
|
|
|
|
{
|
|
|
|
KNotifyClient::event(winId(), "illegal_move", i18n("Illegal move"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Show things when the game is over.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::showGameOver(Color color)
|
|
|
|
{
|
|
|
|
// If the game already was over, do nothing.
|
|
|
|
if (m_gameOver)
|
|
|
|
return;
|
|
|
|
|
|
|
|
statusBar()->message(i18n("End of game"));
|
|
|
|
|
|
|
|
// Get the scores.
|
|
|
|
uint human = m_game->score(humanColor());
|
|
|
|
uint computer = m_game->score(computerColor());
|
|
|
|
|
|
|
|
KExtHighscore::Score score;
|
|
|
|
score.setScore(m_game->score(humanColor()));
|
|
|
|
|
|
|
|
// Show the winner in a messagebox.
|
|
|
|
if ( color == Nobody ) {
|
|
|
|
KNotifyClient::event(winId(), "draw", i18n("Draw!"));
|
|
|
|
TQString s = i18n("Game is drawn!\n\nYou : %1\nComputer: %2")
|
|
|
|
.tqarg(human).tqarg(computer);
|
|
|
|
KMessageBox::information(this, s, i18n("Game Ended"));
|
|
|
|
score.setType(KExtHighscore::Draw);
|
|
|
|
}
|
|
|
|
else if ( humanColor() == color ) {
|
|
|
|
KNotifyClient::event(winId(), "won", i18n("Game won!"));
|
|
|
|
TQString s = i18n("Congratulations, you have won!\n\nYou : %1\nComputer: %2")
|
|
|
|
.tqarg(human).tqarg(computer);
|
|
|
|
KMessageBox::information(this, s, i18n("Game Ended"));
|
|
|
|
score.setType(KExtHighscore::Won);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
KNotifyClient::event(winId(), "lost", i18n("Game lost!"));
|
|
|
|
TQString s = i18n("You have lost the game!\n\nYou : %1\nComputer: %2")
|
|
|
|
.tqarg(human).tqarg(computer);
|
|
|
|
KMessageBox::information(this, s, i18n("Game Ended"));
|
|
|
|
score.setType(KExtHighscore::Lost);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store the result in the highscore file if no cheating was done,
|
|
|
|
// and only if the game was competitive.
|
|
|
|
if (!m_cheating && m_competitiveGame) {
|
|
|
|
KExtHighscore::submitScore(score, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_gameOver = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Saves the game in the config file.
|
|
|
|
//
|
|
|
|
// Only one game at a time can be saved.
|
|
|
|
//
|
|
|
|
|
|
|
|
void KReversi::saveGame(KConfig *config)
|
|
|
|
{
|
|
|
|
// Stop thinking.
|
|
|
|
slotInterrupt();
|
|
|
|
|
|
|
|
// Write the data to the config file.
|
|
|
|
config->writeEntry("State", state());
|
|
|
|
config->writeEntry("Strength", strength());
|
|
|
|
config->writeEntry("Competitive", (int) m_competitiveGame);
|
|
|
|
config->writeEntry("HumanColor", (int) m_humanColor);
|
|
|
|
|
|
|
|
// Write the moves of the game to the config object. This object
|
|
|
|
// saves itself all at once so we don't have to write the moves
|
|
|
|
// to the file ourselves.
|
|
|
|
config->writeEntry("NumberOfMoves", m_game->moveNumber());
|
|
|
|
for (uint i = 0; i < m_game->moveNumber(); i++) {
|
|
|
|
Move move = m_game->move(i);
|
|
|
|
|
|
|
|
TQString moveString;
|
|
|
|
TQString idx;
|
|
|
|
|
|
|
|
moveString.sprintf("%d %d %d", move.x(), move.y(), (int) move.color());
|
|
|
|
idx.sprintf("Move_%d", i + 1);
|
|
|
|
config->writeEntry(idx, moveString);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Actually write the data to file.
|
|
|
|
config->sync();
|
|
|
|
|
|
|
|
// Continue with the move if applicable.
|
|
|
|
slotContinue();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Loads the game. Only one game at a time can be saved.
|
|
|
|
|
|
|
|
bool KReversi::loadGame(KConfig *config)
|
|
|
|
{
|
|
|
|
slotInterrupt(); // stop thinking
|
|
|
|
|
|
|
|
uint nmoves = config->readNumEntry("NumberOfMoves", 0);
|
|
|
|
if (nmoves==0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
m_game->newGame();
|
|
|
|
uint movenumber = 1;
|
|
|
|
while (nmoves--) {
|
|
|
|
// Read one move.
|
|
|
|
TQString idx;
|
|
|
|
idx.sprintf("Move_%d", movenumber++);
|
|
|
|
|
|
|
|
TQStringList s = config->readListEntry(idx, ' ');
|
|
|
|
uint x = (*s.at(0)).toUInt();
|
|
|
|
uint y = (*s.at(1)).toUInt();
|
|
|
|
Color color = (Color)(*s.at(2)).toInt();
|
|
|
|
|
|
|
|
Move move(color, x, y);
|
|
|
|
m_game->doMove(move);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_humanColor = (Color) config->readNumEntry("HumanColor");
|
|
|
|
m_competitiveGame = (bool) config->readNumEntry("Competitive");
|
|
|
|
|
|
|
|
m_gameView->updateBoard(TRUE);
|
|
|
|
setState(State(config->readNumEntry("State")));
|
|
|
|
setStrength(config->readNumEntry("Strength", 1));
|
|
|
|
|
|
|
|
if (interrupted())
|
|
|
|
slotContinue();
|
|
|
|
else {
|
|
|
|
// Computer makes first move.
|
|
|
|
if (m_humanColor != m_game->toMove())
|
|
|
|
computerMakeMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::saveProperties(KConfig *c)
|
|
|
|
{
|
|
|
|
saveGame(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::readProperties(KConfig *config) {
|
|
|
|
loadGame(config);
|
|
|
|
m_gameOver = false;
|
|
|
|
m_cheating = false; // FIXME: Is this true? It isn't saved.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::showHighScoreDialog()
|
|
|
|
{
|
|
|
|
KExtHighscore::show(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::slotEditSettings()
|
|
|
|
{
|
|
|
|
// If we are already editing the settings, then do nothing.
|
|
|
|
if (KConfigDialog::showDialog("settings"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
KConfigDialog *dialog = new KConfigDialog(this, "settings", Prefs::self(),
|
|
|
|
KDialogBase::Swallow);
|
|
|
|
Settings *general = new Settings(0, "General");
|
|
|
|
|
|
|
|
dialog->addPage(general, i18n("General"), "package_settings");
|
|
|
|
connect(dialog, TQT_SIGNAL(settingsChanged()), TQT_TQOBJECT(this), TQT_SLOT(loadSettings()));
|
|
|
|
dialog->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::configureNotifications()
|
|
|
|
{
|
|
|
|
KNotifyDialog::configure(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::loadSettings()
|
|
|
|
{
|
|
|
|
m_humanColor = (Color) Prefs::humanColor();
|
|
|
|
setStrength(Prefs::skill());
|
|
|
|
|
|
|
|
// m_competitiveGame is set at the start of a game and can only be
|
|
|
|
// downgraded during the game, never upgraded.
|
|
|
|
if ( !Prefs::competitiveGameChoice() )
|
|
|
|
m_competitiveGame = false;
|
|
|
|
|
|
|
|
m_gameView->loadSettings();
|
|
|
|
|
|
|
|
// Update the color of the human and the computer.
|
|
|
|
m_gameView->setHumanColor(humanColor());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KReversi::isPlaying() const
|
|
|
|
{
|
|
|
|
return ( m_game->moveNumber() != 0 && !m_gameOver );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::setState(State newState)
|
|
|
|
{
|
|
|
|
m_state = newState;
|
|
|
|
|
|
|
|
if (m_state == Thinking){
|
|
|
|
kapp->setOverrideCursor(waitCursor);
|
|
|
|
stopAction->setEnabled(true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
kapp->restoreOverrideCursor();
|
|
|
|
stopAction->setEnabled(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
continueAction->setEnabled(interrupted());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KReversi::queryExit()
|
|
|
|
{
|
|
|
|
if ( isPlaying() )
|
|
|
|
KExtHighscore::submitScore(KExtHighscore::Lost, this);
|
|
|
|
|
|
|
|
return KZoomMainWindow::queryExit();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::writeZoomSetting(uint zoom)
|
|
|
|
{
|
|
|
|
Prefs::setZoom(zoom);
|
|
|
|
Prefs::writeConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint KReversi::readZoomSetting() const
|
|
|
|
{
|
|
|
|
return Prefs::zoom();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KReversi::writeMenubarVisibleSetting(bool visible)
|
|
|
|
{
|
|
|
|
Prefs::setMenubarVisible(visible);
|
|
|
|
Prefs::writeConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KReversi::menubarVisibleSetting() const
|
|
|
|
{
|
|
|
|
return Prefs::menubarVisible();
|
|
|
|
}
|