You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/kjumpingcube/kcubeboxwidget.cpp

712 lines
15 KiB

/* ****************************************************************************
This file is part of the game 'KJumpingCube'
Copyright (C) 1998-2000 by Matthias Kiefer
<matthias.kiefer@gmx.de>
This program 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 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**************************************************************************** */
#include "kcubeboxwidget.h"
#include <kapplication.h>
#include <kconfig.h>
#include <tqlayout.h>
#include <tqtimer.h>
#include <assert.h>
#include <kcursor.h>
#include "prefs.h"
KCubeBoxWidget::KCubeBoxWidget(const int d,TQWidget *parent,const char *name)
: TQWidget(parent,name),
CubeBoxBase<KCubeWidget>(d)
{
init();
}
KCubeBoxWidget::KCubeBoxWidget(CubeBox& box,TQWidget *parent,const char *name)
:TQWidget(parent,name),
CubeBoxBase<KCubeWidget>(box.dim())
{
init();
int i,j;
for(i=0;i<dim();i++)
for(j=0;j<dim();j++)
{
*cubes[i][j]=*box[i][j];
}
currentPlayer=(KCubeBoxWidget::Player)box.player();
}
KCubeBoxWidget::KCubeBoxWidget(const KCubeBoxWidget& box,TQWidget *parent,const char *name)
:TQWidget(parent,name),
CubeBoxBase<KCubeWidget>(box.dim())
{
init();
int i,j;
for(i=0;i<dim();i++)
for(j=0;j<dim();j++)
{
*cubes[i][j]=*box.cubes[i][j];
}
currentPlayer=box.currentPlayer;
}
KCubeBoxWidget::~KCubeBoxWidget()
{
if(isActive())
stopActivities();
if(cubes)
deleteCubes();
if(undoBox)
delete undoBox;
}
void KCubeBoxWidget::loadSettings(){
setColor(KCubeBoxWidget::One, Prefs::color1());
setColor(KCubeBoxWidget::Two, Prefs::color2());
setDim(Prefs::cubeDim());
brain.setSkill( Prefs::skill() );
setComputerplayer(KCubeBoxWidget::One, Prefs::computerPlayer1());
setComputerplayer(KCubeBoxWidget::Two, Prefs::computerPlayer2());
checkComputerplayer(currentPlayer);
}
KCubeBoxWidget& KCubeBoxWidget::operator=(const KCubeBoxWidget& box)
{
if(this!=&box)
{
if(dim()!=box.dim())
{
setDim(box.dim());
}
for(int i=0;i<dim();i++)
for(int j=0;j<dim();j++)
{
*cubes[i][j]=*box.cubes[i][j];
}
currentPlayer=box.currentPlayer;
}
return *this;
}
KCubeBoxWidget& KCubeBoxWidget::operator=(CubeBox& box)
{
if(dim()!=box.dim())
{
setDim(box.dim());
}
for(int i=0;i<dim();i++)
for(int j=0;j<dim();j++)
{
*cubes[i][j]=*box[i][j];
}
currentPlayer=(KCubeBoxWidget::Player)box.player();
return *this;
}
void KCubeBoxWidget::reset()
{
stopActivities();
int i,j;
for(i=0;i<dim();i++)
for(j=0;j<dim();j++)
{
cubes[i][j]->reset();
}
KCubeWidget::enableClicks(true);
currentPlayer=One;
emit playerChanged(One);
checkComputerplayer(One);
}
void KCubeBoxWidget::undo()
{
if(isActive())
return;
Player oldPlayer=currentPlayer;
*this=*undoBox;
if(oldPlayer!=currentPlayer)
emit playerChanged(currentPlayer);
checkComputerplayer(currentPlayer);
}
void KCubeBoxWidget::getHint()
{
if(isActive())
return;
int d=dim();
for(int i=0;i<d;i++)
for(int j=0;j<d;j++)
{
cubes[i][j]->stopHint();
}
int row=0,column=0;
CubeBox field=*this;
emit startedThinking();
bool canceled=!brain.getHint(row,column,(CubeBox::Player)currentPlayer,field);
emit stoppedThinking();
if(canceled)
{
return; // return if thinking was stopped
}
cubes[row][column]->showHint();
}
void KCubeBoxWidget::setColor(Player player,TQPalette color)
{
KCubeWidget::setColor((Cube::Owner)player,color);
for(int row=0;row<dim();row++)
for(int col=0;col<dim();col++)
{
cubes[row][col]->updateColors();
}
}
void KCubeBoxWidget::setDim(int d)
{
if(d != dim())
{
undoBox->setDim(d);
CubeBoxBase<KCubeWidget>::setDim(d);
}
}
void KCubeBoxWidget::setComputerplayer(Player player,bool flag)
{
if(player==One)
computerPlOne=flag;
else if(player==Two)
computerPlTwo=flag;
}
void KCubeBoxWidget::stopActivities()
{
if(moveTimer->isActive())
{
stopLoop();
emit stoppedMoving();
}
if(brain.isActive())
{
brain.stop();
emit stoppedThinking();
}
}
void KCubeBoxWidget::saveProperties(KConfigBase* config)
{
if(isMoving())
{
stopActivities();
undo();
}
else if(brain.isActive())
stopActivities();
// save current player
config->writeEntry("onTurn",(int)currentPlayer);
TQStrList list;
list.setAutoDelete(true);
TQString owner, value, key;
int cubeDim=dim();
for(int row=0; row < cubeDim ; row++)
for(int column=0; column < cubeDim ; column++)
{
key.sprintf("%u,%u",row,column);
owner.sprintf("%u",cubes[row][column]->owner());
value.sprintf("%u",cubes[row][column]->value());
list.append(owner.ascii());
list.append(value.ascii());
config->writeEntry(key , list);
list.clear();
}
config->writeEntry("CubeDim",dim());
}
void KCubeBoxWidget::readProperties(KConfigBase* config)
{
TQStrList list;
list.setAutoDelete(true);
TQString owner, value, key;
setDim(config->readNumEntry("CubeDim",5));
int cubeDim=dim();
for(int row=0; row < cubeDim ; row++)
for(int column=0; column < cubeDim ; column++)
{
key.sprintf("%u,%u",row,column);
config->readListEntry(key, list);
owner=list.first();
value=list.next();
cubes[row][column]->setOwner((KCubeWidget::Owner)owner.toInt());
cubes[row][column]->setValue(value.toInt());
list.clear();
}
// set current player
int onTurn=config->readNumEntry("onTurn",1);
currentPlayer=(Player)onTurn;
emit playerChanged(onTurn);
checkComputerplayer((Player)onTurn);
}
/* ***************************************************************** **
** slots **
** ***************************************************************** */
void KCubeBoxWidget::setWaitCursor()
{
setCursor(KCursor::waitCursor());
}
void KCubeBoxWidget::setNormalCursor()
{
setCursor(KCursor::handCursor());
}
void KCubeBoxWidget::stopHint()
{
int d=dim();
for(int i=0;i<d;i++)
for(int j=0;j<d;j++)
{
cubes[i][j]->stopHint();
}
}
bool KCubeBoxWidget::checkClick(int row,int column, bool isClick)
{
if(isActive())
return false;
// make the game start when computer player is player one and user clicks
if(isClick && currentPlayer == One && computerPlOne)
{
checkComputerplayer(currentPlayer);
return false;
}
else if((Cube::Owner)currentPlayer==cubes[row][column]->owner() ||
cubes[row][column]->owner()==Cube::Nobody)
{
doMove(row,column);
return true;
}
else
return false;
}
void KCubeBoxWidget::checkComputerplayer(Player player)
{
// checking if a process is running or the Widget isn't shown yet
if(isActive() || !isVisibleToTLW())
return;
if((player==One && computerPlOne && currentPlayer==One)
|| (player==Two && computerPlTwo && currentPlayer==Two))
{
KCubeWidget::enableClicks(false);
CubeBox field(*this);
int row=0,column=0;
emit startedThinking();
bool canceled=!brain.getHint(row,column,(CubeBoxBase<Cube>::Player)player,field);
emit stoppedThinking();
if(!canceled)
{
cubes[row][column]->showHint(500,2);
bool result=checkClick(row,column,false);
assert(result);
}
}
}
/* ***************************************************************** **
** status functions **
** ***************************************************************** */
bool KCubeBoxWidget::isActive() const
{
bool flag=false;
if(moveTimer->isActive())
flag=true;
else if(brain.isActive())
flag=true;
return flag;
}
bool KCubeBoxWidget::isMoving() const
{
return moveTimer->isActive();
}
bool KCubeBoxWidget::isComputer(Player player) const
{
if(player==One)
return computerPlOne;
else
return computerPlTwo;
}
int KCubeBoxWidget::skill() const
{
return brain.skill();
}
TQPalette KCubeBoxWidget::color(Player forWhom)
{
return KCubeWidget::color((KCubeWidget::Owner)forWhom);
}
/* ***************************************************************** **
** initializing functions **
** ***************************************************************** */
void KCubeBoxWidget::init()
{
initCubes();
undoBox=new CubeBox(dim());
currentPlayer=One;
moveDelay=100;
moveTimer=new TQTimer(this);
computerPlOne=false;
computerPlTwo=false;
KCubeWidget::enableClicks(true);
loadSettings();
connect(moveTimer,TQT_SIGNAL(timeout()),TQT_SLOT(nextLoopStep()));
connect(this,TQT_SIGNAL(startedThinking()),TQT_SLOT(setWaitCursor()));
connect(this,TQT_SIGNAL(stoppedThinking()),TQT_SLOT(setNormalCursor()));
connect(this,TQT_SIGNAL(startedMoving()),TQT_SLOT(setWaitCursor()));
connect(this,TQT_SIGNAL(stoppedMoving()),TQT_SLOT(setNormalCursor()));
connect(this,TQT_SIGNAL(playerWon(int)),TQT_SLOT(stopActivities()));
setNormalCursor();
emit playerChanged(One);
}
void KCubeBoxWidget::initCubes()
{
const int s=dim();
int i,j;
// create Layout
layout=new TQGridLayout(this,s,s);
for(i=0;i<s;i++)
{
layout->setRowStretch(i,1);
layout->setColStretch(i,1);
}
// create new cubes
cubes = new KCubeWidget**[s];
for(i=0;i<s;i++)
{
cubes[i]=new KCubeWidget*[s];
}
for(i=0;i<s;i++)
for(j=0;j<s;j++)
{
cubes[i][j]=new KCubeWidget(this);
cubes[i][j]->setCoordinates(i,j);
layout->addWidget(cubes[i][j],i,j);
cubes[i][j]->show();
connect(cubes[i][j],TQT_SIGNAL(clicked(int,int,bool)),TQT_SLOT(stopHint()));
connect(cubes[i][j],TQT_SIGNAL(clicked(int,int,bool)),TQT_SLOT(checkClick(int,int,bool)));
}
// initialize cubes
int max=dim()-1;
cubes[0][0]->setMax(2);
cubes[0][max]->setMax(2);
cubes[max][0]->setMax(2);
cubes[max][max]->setMax(2);
for(i=1;i<max;i++)
{
cubes[i][0]->setMax(3);
cubes[i][max]->setMax(3);
cubes[0][i]->setMax(3);
cubes[max][i]->setMax(3);
}
for(i=1;i<max;i++)
for(j=1;j<max;j++)
{
cubes[i][j]->setMax(4);
}
}
TQSize KCubeBoxWidget::sizeHint() const
{
return TQSize(400,400);
}
void KCubeBoxWidget::deleteCubes()
{
if(layout)
delete layout;
CubeBoxBase<KCubeWidget>::deleteCubes();
}
/* ***************************************************************** **
** other private functions **
** ***************************************************************** */
void KCubeBoxWidget::doMove(int row,int column)
{
// if a move hasn't finished yet don't do another move
if(isActive())
return;
// for undo-function copy field
*undoBox=*this;
cubes[row][column]->increase((Cube::Owner)currentPlayer);
if(cubes[row][column]->overMax())
{
KCubeWidget::enableClicks(false);
startLoop();
}
else
changePlayer();
}
void KCubeBoxWidget::startLoop()
{
emit startedMoving();
KCubeWidget::enableClicks(false);
loop.row=0;
loop.column=0;
loop.finished=true;
moveTimer->start(moveDelay);
}
void KCubeBoxWidget::stopLoop()
{
moveTimer->stop();
emit stoppedMoving();
KCubeWidget::enableClicks(true);
}
void KCubeBoxWidget::nextLoopStep()
{
// search cube with to many points
while(!cubes[loop.row][loop.column]->overMax())
{
loop.column++;
if(loop.column==dim())
{
if(loop.row==dim()-1)
{
if(!loop.finished)
{
loop.row=0;
loop.column=0;
loop.finished=true;
return;
}
else // loop finished
{
stopLoop();
changePlayer();
return;
}
}
else
{
loop.row++;
loop.column=0;
}
}
}
increaseNeighbours(currentPlayer,loop.row,loop.column);
cubes[loop.row][loop.column]->decrease();
loop.finished=false;
if(hasPlayerWon(currentPlayer))
{
emit playerWon((int)currentPlayer);
stopLoop();
return;
}
}
bool KCubeBoxWidget::hasPlayerWon(Player player)
{
for(int i=0;i<dim();i++)
for(int j=0;j<dim();j++)
{
if(cubes[i][j]->owner()!=(Cube::Owner)player)
{
return false;
}
}
return true;
}
KCubeBoxWidget::Player KCubeBoxWidget::changePlayer()
{
currentPlayer=(currentPlayer==One)? Two : One;
emit playerChanged(currentPlayer);
checkComputerplayer(currentPlayer);
KCubeWidget::enableClicks(true);
return currentPlayer;
}
void KCubeBoxWidget::increaseNeighbours(KCubeBoxWidget::Player forWhom,int row,int column)
{
KCubeWidget::Owner _player = (KCubeWidget::Owner)(forWhom);
if(row==0)
{
if(column==0) // top left corner
{
cubes[0][1]->increase(_player);
cubes[1][0]->increase(_player);
return;
}
else if(column==dim()-1) // top right corner
{
cubes[0][dim()-2]->increase(_player);
cubes[1][dim()-1]->increase(_player);
return;
}
else // top edge
{
cubes[0][column-1]->increase(_player);
cubes[0][column+1]->increase(_player);
cubes[1][column]->increase(_player);
return;
}
}
else if(row==dim()-1)
{
if(column==0) // left bottom corner
{
cubes[dim()-2][0]->increase(_player);
cubes[dim()-1][1]->increase(_player);
return;
}
else if(column==dim()-1) // right bottom corner
{
cubes[dim()-2][dim()-1]->increase(_player);
cubes[dim()-1][dim()-2]->increase(_player);
return;
}
else // bottom edge
{
cubes[dim()-1][column-1]->increase(_player);
cubes[dim()-1][column+1]->increase(_player);
cubes[dim()-2][column]->increase(_player);
return;
}
}
else if(column==0) // left edge
{
cubes[row-1][0]->increase(_player);
cubes[row+1][0]->increase(_player);
cubes[row][1]->increase(_player);
return;
}
else if(column==dim()-1) // right edge
{
cubes[row-1][dim()-1]->increase(_player);
cubes[row+1][dim()-1]->increase(_player);
cubes[row][dim()-2]->increase(_player);
return;
}
else
{
cubes[row][column-1]->increase(_player);
cubes[row][column+1]->increase(_player);
cubes[row-1][column]->increase(_player);
cubes[row+1][column]->increase(_player);
return;
}
}
#include "kcubeboxwidget.moc"