mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-27 00:19:25 -05:00
082d5732b0
git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@2346 b45a01b8-16f6-495d-af2f-9b41ad6348cc
771 lines
23 KiB
C++
771 lines
23 KiB
C++
/*
|
|
QSoloCards is a collection of Solitaire card games written using Qt
|
|
Copyright (C) 2009 Steve Moore
|
|
|
|
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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "KlondikeBoard.h"
|
|
#include <QtGui/QMessageBox>
|
|
|
|
#include "CardDeck.h"
|
|
#include "CardPixmaps.h"
|
|
#include "CardAnimationLock.h"
|
|
|
|
const QString KlondikeBoard::GameTypeKeyStr("GameType");
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
KlondikeBoard::KlondikeBoard(QWidget * pWidget)
|
|
:GameBoard(pWidget,QString(tr("Klondike Solitaire")).trimmed(),QString("Klondike")),
|
|
m_pDeck(NULL),
|
|
m_pFlipDeck(NULL),
|
|
m_homeVector(),
|
|
m_stackVector(),
|
|
m_cheat(false),
|
|
m_gameType(KlondikeBoard::FlipOne),
|
|
m_flipNum(0),
|
|
m_sToSFlipAni()
|
|
{
|
|
this->setHelpFile(":/help/KlondikeHelp.html");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
KlondikeBoard::~KlondikeBoard()
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::undoMove()
|
|
{
|
|
bool emptyBefore=false;
|
|
bool emptyAfter=false;
|
|
|
|
emptyBefore=m_pDeck->isEmpty();
|
|
|
|
GameBoard::undoMove();
|
|
|
|
emptyAfter=m_pDeck->isEmpty();
|
|
|
|
// if we undone a redeal decrement the flip count
|
|
if (!emptyBefore && emptyAfter)
|
|
{
|
|
this->m_flipNum--;
|
|
if (!(KlondikeBoard::FlipOne==this->m_gameType &&
|
|
this->m_flipNum<2) &&
|
|
!(KlondikeBoard::FlipThree==this->m_gameType))
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(false);
|
|
this->m_pDeck->updateStack();
|
|
}
|
|
else
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(true);
|
|
this->m_pDeck->updateStack();
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::redoMove()
|
|
{
|
|
bool emptyBefore=false;
|
|
bool emptyAfter=false;
|
|
|
|
emptyBefore=m_pDeck->isEmpty();
|
|
|
|
GameBoard::redoMove();
|
|
|
|
emptyAfter=m_pDeck->isEmpty();
|
|
|
|
// if we are redoing a redeal increment the flip count
|
|
if (emptyBefore && !emptyAfter)
|
|
{
|
|
this->m_flipNum++;
|
|
|
|
if (!(KlondikeBoard::FlipOne==this->m_gameType &&
|
|
this->m_flipNum<2) &&
|
|
!(KlondikeBoard::FlipThree==this->m_gameType))
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(false);
|
|
this->m_pDeck->updateStack();
|
|
}
|
|
else
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(true);
|
|
this->m_pDeck->updateStack();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::restartGame()
|
|
{
|
|
// call the base class to rewind the undo stack
|
|
GameBoard::restartGame();
|
|
|
|
// reset the flip count
|
|
this->m_flipNum=0;
|
|
// and set the redeal circle depending on game type
|
|
if (KlondikeBoard::NoRedeals==this->m_gameType)
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(false);
|
|
}
|
|
else
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(true);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool KlondikeBoard::getHint(CardStack * & pFromStack,
|
|
unsigned int & index,
|
|
CardStack * & pToStack)
|
|
{
|
|
// first see if we can move anything to one of the home stacks.
|
|
PlayingCardVector moveCards;
|
|
unsigned int i;
|
|
bool matchFound=false;
|
|
|
|
|
|
// ok check to see if we have a card from the stacks that can
|
|
// be added to a home stack
|
|
for (i=0;i<this->m_stackVector.size() && !matchFound;i++)
|
|
{
|
|
if (!this->m_stackVector[i]->isEmpty())
|
|
{
|
|
const PlayingCardVector & currCards=this->m_stackVector[i]->getCardVector();
|
|
moveCards.clear();
|
|
moveCards.push_back(currCards[currCards.size()-1]); // just get the last card since we are moving to the home stack
|
|
index=currCards.size()-1;
|
|
|
|
for (unsigned int j=0;j<this->m_homeVector.size();j++)
|
|
{
|
|
if (this->m_homeVector[j]->canAddCards(moveCards))
|
|
{
|
|
pToStack=this->m_homeVector[j];
|
|
pFromStack=this->m_stackVector[i];
|
|
matchFound=true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// next check for stack to stack moves.
|
|
if (!matchFound)
|
|
{
|
|
moveCards.clear();
|
|
pToStack=NULL;
|
|
pFromStack=NULL;
|
|
|
|
for (i=0;i<this->m_stackVector.size() && !matchFound;i++)
|
|
{
|
|
moveCards.clear();
|
|
if (!this->m_stackVector[i]->isEmpty() &&
|
|
this->m_stackVector[i]->getMovableCards(moveCards,index))
|
|
{
|
|
// we want to eliminate a move that starts with a stack that
|
|
// has a faceup king as the first card. We will just end up
|
|
// suggesting to move it to another empty row. Which is not
|
|
// really a move.
|
|
if (PlayingCard::King==moveCards[0].getIndex() &&
|
|
moveCards.size()== this->m_stackVector[i]->getCardVector().size())
|
|
{
|
|
continue;
|
|
}
|
|
for (unsigned int j=0;j<this->m_stackVector.size();j++)
|
|
{
|
|
if (this->m_stackVector[i]!=this->m_stackVector[j] &&
|
|
this->m_stackVector[j]->canAddCards(moveCards))
|
|
{
|
|
pToStack=this->m_stackVector[j];
|
|
pFromStack=this->m_stackVector[i];
|
|
matchFound=true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// check the flip deck. We can just call getMovableCards for it
|
|
// since, it will always be just one card.
|
|
if (!matchFound)
|
|
{
|
|
moveCards.clear();
|
|
pToStack=NULL;
|
|
pFromStack=NULL;
|
|
|
|
if (!this->m_pFlipDeck->isEmpty() &&
|
|
this->m_pFlipDeck->getMovableCards(moveCards,index))
|
|
{
|
|
// first see if we can send a card to one of the home
|
|
// stacks
|
|
for(i=0;i<this->m_homeVector.size();i++)
|
|
{
|
|
if (this->m_homeVector[i]->canAddCards(moveCards))
|
|
{
|
|
pToStack=this->m_homeVector[i];
|
|
pFromStack=this->m_pFlipDeck;
|
|
matchFound=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if no match now check to see if we can add the card to the
|
|
// normal stacks
|
|
if (!matchFound)
|
|
{
|
|
for(i=0;i<this->m_stackVector.size();i++)
|
|
{
|
|
if (this->m_stackVector[i]->canAddCards(moveCards))
|
|
{
|
|
pToStack=this->m_stackVector[i];
|
|
pFromStack=this->m_pFlipDeck;
|
|
matchFound=true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return matchFound;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::newGame()
|
|
{
|
|
// stop any animation of flipping cards
|
|
m_sToSFlipAni.stopAni();
|
|
// call the base class
|
|
GameBoard::newGame();
|
|
|
|
CardDeck deck;
|
|
unsigned int i;
|
|
|
|
this->m_flipNum=0;
|
|
|
|
// only show the redeal circle in the cases that we can redeal
|
|
if (KlondikeBoard::NoRedeals==this->m_gameType)
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(false);
|
|
}
|
|
else
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(true);
|
|
}
|
|
|
|
|
|
this->m_pFlipDeck->cardsToShow(((KlondikeBoard::FlipThree==this->m_gameType)?3:1));
|
|
|
|
|
|
|
|
while(!deck.isEmpty())
|
|
{
|
|
this->m_pDeck->addCard(deck.next());
|
|
}
|
|
|
|
|
|
DealItemVector dealItemVector;
|
|
|
|
|
|
// Create the dealItemVector to direct the DealAnimation object on
|
|
// how to deal the cards.
|
|
for (i=0;i<this->m_stackVector.size();i++)
|
|
{
|
|
dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck));
|
|
|
|
unsigned int j;
|
|
|
|
for (j=0;j<i+1;j++)
|
|
{
|
|
// add the items to tell how to deal the cards to the stack
|
|
// we want to flip the last card in each stack.
|
|
if (i==j)
|
|
{
|
|
dealItemVector[i].addCard(true);
|
|
}
|
|
else
|
|
{
|
|
dealItemVector[i].addCard(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ok now start the deal. We don't need a move record for this item.
|
|
m_dealAni.dealCards(dealItemVector,false);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::addGameMenuItems(QMenu & menu)
|
|
{
|
|
QActionGroup * pFlipCardsGroup=new QActionGroup(&menu);
|
|
|
|
|
|
QAction * pFlipOneAction=new QAction(tr("Flip one").trimmed(),pFlipCardsGroup);
|
|
pFlipOneAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_1));
|
|
pFlipOneAction->setCheckable(true);
|
|
connect(pFlipOneAction,SIGNAL(triggered()),
|
|
this,SLOT(slotSetFlipOne()));
|
|
|
|
QAction * pFlipThreeAction=new QAction(tr("Flip three").trimmed(),pFlipCardsGroup);
|
|
pFlipThreeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_3));
|
|
pFlipThreeAction->setCheckable(true);
|
|
connect(pFlipThreeAction,SIGNAL(triggered()),
|
|
this,SLOT(slotSetFlipThree()));
|
|
|
|
QAction * pNoRedealsAction=new QAction(tr("No redeals (flip one)").trimmed(),pFlipCardsGroup);
|
|
pNoRedealsAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_0));
|
|
pNoRedealsAction->setCheckable(true);
|
|
connect(pNoRedealsAction,SIGNAL(triggered()),
|
|
this,SLOT(slotSetNoRedeals()));
|
|
|
|
// select the correct item in the list
|
|
switch (this->m_gameType)
|
|
{
|
|
case KlondikeBoard::FlipOne:
|
|
pFlipOneAction->setChecked(true);
|
|
break;
|
|
|
|
case KlondikeBoard::FlipThree:
|
|
pFlipThreeAction->setChecked(true);
|
|
break;
|
|
|
|
case KlondikeBoard::NoRedeals:
|
|
pNoRedealsAction->setChecked(true);
|
|
break;
|
|
};
|
|
|
|
|
|
menu.addAction(pFlipOneAction);
|
|
menu.addAction(pFlipThreeAction);
|
|
menu.addAction(pNoRedealsAction);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::loadSettings(const QSettings & settings)
|
|
{
|
|
int gameType=settings.value(this->GameTypeKeyStr,KlondikeBoard::FlipOne).toInt();
|
|
|
|
switch (gameType)
|
|
{
|
|
case KlondikeBoard::NoRedeals:
|
|
this->m_gameType=KlondikeBoard::NoRedeals;
|
|
break;
|
|
|
|
case KlondikeBoard::FlipThree:
|
|
this->m_gameType=KlondikeBoard::FlipThree;
|
|
break;
|
|
|
|
case KlondikeBoard::FlipOne:
|
|
default:
|
|
this->m_gameType=KlondikeBoard::FlipOne;
|
|
break;
|
|
};
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::saveSettings(QSettings & settings)
|
|
{
|
|
settings.setValue(this->GameTypeKeyStr,this->m_gameType);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::setCheat(bool cheat)
|
|
{
|
|
this->m_cheat=cheat;
|
|
|
|
for(unsigned int i=0;i<this->m_stackVector.size();i++)
|
|
{
|
|
m_stackVector[i]->setCheat(cheat);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::slotFlipCards(CardStack * pCardStack,
|
|
unsigned int index)
|
|
{
|
|
Q_UNUSED(pCardStack);
|
|
Q_UNUSED(index);
|
|
// just use the game type to indicate the number of flip cards
|
|
// the enum is assigned the number of cards that will be flipped
|
|
// the exception is the NoRedeals in that case we are just flipping
|
|
// one card.
|
|
unsigned int numFlipCards=this->m_gameType;
|
|
if (KlondikeBoard::NoRedeals==this->m_gameType)
|
|
{
|
|
numFlipCards=KlondikeBoard::FlipOne;
|
|
}
|
|
|
|
|
|
m_sToSFlipAni.moveCards(m_pFlipDeck,m_pDeck,numFlipCards);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::slotRedealCards(CardStack * pCardStack)
|
|
{
|
|
Q_UNUSED(pCardStack);
|
|
// ignore an attempt to redeal if the game type is NoRedeals.
|
|
// otherwise take all the cards from the Flip stack and put them back
|
|
// in the deal stack
|
|
if (KlondikeBoard::NoRedeals!=this->m_gameType &&
|
|
((KlondikeBoard::FlipOne==this->m_gameType &&
|
|
this->m_flipNum<2) ||
|
|
KlondikeBoard::FlipThree==this->m_gameType))
|
|
{
|
|
unsigned int numFlipCards=this->m_gameType;
|
|
if (KlondikeBoard::NoRedeals==this->m_gameType)
|
|
{
|
|
numFlipCards=KlondikeBoard::FlipOne;
|
|
}
|
|
|
|
// flip the cards back. Flip the cards back over. Show the bottom 3 if in FlipThree mode. Otherwise
|
|
// just show one.
|
|
m_sToSFlipAni.moveCards(m_pDeck,m_pFlipDeck,this->m_pFlipDeck->getCardVector().size(),numFlipCards);
|
|
|
|
this->m_flipNum++;
|
|
|
|
if (!(KlondikeBoard::FlipOne==this->m_gameType &&
|
|
this->m_flipNum<2) &&
|
|
!(KlondikeBoard::FlipThree==this->m_gameType))
|
|
{
|
|
this->m_pDeck->setShowRedealCircle(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if a demo is running stop it. Can't redeal any more.
|
|
this->stopDemo();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::slotStackCardsClicked(CardStack * pCardStack,
|
|
const PlayingCardVector & cardVector,
|
|
const CardMoveRecord & startMoveRecord)
|
|
{
|
|
unsigned int i=0;
|
|
CardStack * pFoundStack=NULL;
|
|
|
|
if (NULL==pCardStack)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// first see if the card can be added to the sent home stack
|
|
if (cardVector.size()==1)
|
|
{
|
|
for(i=0;i<this->m_homeVector.size();i++)
|
|
{
|
|
if (pCardStack!=this->m_homeVector[i] &&
|
|
this->m_homeVector[i]->canAddCards(cardVector))
|
|
{
|
|
pFoundStack=this->m_homeVector[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we did not find a match look at the stacks.
|
|
// the home will use the same logic so just call that slot
|
|
if (NULL==pFoundStack)
|
|
{
|
|
this->slotHomeCardsClicked(pCardStack,cardVector,startMoveRecord);
|
|
}
|
|
|
|
if (pFoundStack)
|
|
{
|
|
CardMoveRecord moveRecord(startMoveRecord);
|
|
pFoundStack->addCards(cardVector,moveRecord,true);
|
|
|
|
// perform the move of the cards and animate it if animations
|
|
// are enabled
|
|
m_sToSAniMove.moveCards(moveRecord);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::slotHomeCardsClicked(CardStack * pCardStack,
|
|
const PlayingCardVector & cardVector,
|
|
const CardMoveRecord & startMoveRecord)
|
|
{
|
|
unsigned int i=0;
|
|
CardStack * pFoundStack=NULL;
|
|
|
|
if (NULL==pCardStack)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(i=0;i<this->m_stackVector.size();i++)
|
|
{
|
|
if (pCardStack!=this->m_stackVector[i] &&
|
|
this->m_stackVector[i]->canAddCards(cardVector))
|
|
{
|
|
pFoundStack=this->m_stackVector[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pFoundStack)
|
|
{
|
|
CardMoveRecord moveRecord(startMoveRecord);
|
|
pFoundStack->addCards(cardVector,moveRecord,true);
|
|
|
|
// perform the move of the cards and animate it if animations
|
|
// are enabled
|
|
m_sToSAniMove.moveCards(moveRecord);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::slotSetNoRedeals()
|
|
{
|
|
this->m_gameType=KlondikeBoard::NoRedeals;
|
|
this->newGame();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::slotSetFlipOne()
|
|
{
|
|
this->m_gameType=KlondikeBoard::FlipOne;
|
|
this->newGame();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::slotSetFlipThree()
|
|
{
|
|
this->m_gameType=KlondikeBoard::FlipThree;
|
|
this->newGame();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::calcScore()
|
|
{
|
|
int score=0;
|
|
|
|
for(unsigned int i=0;i<this->m_homeVector.size();i++)
|
|
{
|
|
score+=this->m_homeVector[i]->score();
|
|
}
|
|
|
|
emit scoreChanged(score,"");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::resizeEvent (QResizeEvent * event)
|
|
{
|
|
unsigned int i;
|
|
|
|
GameBoard::resizeEvent(event);
|
|
|
|
|
|
QSize cardSize(CardPixmaps::getInst().getCardSize());
|
|
|
|
QPointF currPos(GameBoard::LayoutSpacing,GameBoard::LayoutSpacing);
|
|
|
|
m_pDeck->setPos(currPos);
|
|
|
|
currPos.rx()+=GameBoard::LayoutSpacing + cardSize.width();
|
|
|
|
m_pFlipDeck->setPos(currPos);
|
|
|
|
currPos.rx()+=GameBoard::LayoutSpacing*3 + cardSize.width()*3;
|
|
|
|
|
|
for (i=0;i<m_homeVector.size();i++)
|
|
{
|
|
m_homeVector[i]->setPos(currPos);
|
|
currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing;
|
|
}
|
|
|
|
currPos.setY(GameBoard::LayoutSpacing*2+cardSize.height());
|
|
currPos.setX(GameBoard::LayoutSpacing*2+cardSize.width());
|
|
for (i=0;i<m_stackVector.size();i++)
|
|
{
|
|
m_stackVector[i]->setPos(currPos);
|
|
currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool KlondikeBoard::runDemo(bool stopWhenNoMore)
|
|
{
|
|
bool rc=true;
|
|
|
|
if (!GameBoard::runDemo(false))
|
|
{
|
|
if (!m_pDeck->isEmpty())
|
|
{
|
|
this->slotFlipCards();
|
|
}
|
|
else if (!m_pFlipDeck->isEmpty())
|
|
{
|
|
this->slotRedealCards();
|
|
}
|
|
else if (stopWhenNoMore)
|
|
{
|
|
stopDemo();
|
|
rc=false;
|
|
}
|
|
else
|
|
{
|
|
rc=false;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void KlondikeBoard::createStacks()
|
|
{
|
|
setCardResizeAlg(8,ResizeByWidth);
|
|
|
|
|
|
unsigned int i;
|
|
|
|
// first create the home widgets where the cards need to be eventually stacked to
|
|
// win the game.
|
|
for(i=0;i<4;i++)
|
|
{
|
|
this->m_homeVector.push_back(new KlondikeHomeStack);
|
|
this->m_scene.addItem(m_homeVector[i]);
|
|
this->connect(this->m_homeVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)),
|
|
this,SLOT(slotCardsMoved(CardMoveRecord)));
|
|
this->connect(this->m_homeVector[i],SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)),
|
|
this,SLOT(slotHomeCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)));
|
|
}
|
|
|
|
// now create the 7 rows for the stacks.
|
|
for (i=0;i<7;i++)
|
|
{
|
|
this->m_stackVector.push_back(new KlondikeStack);
|
|
this->m_scene.addItem(m_stackVector[i]);
|
|
this->connect(this->m_stackVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)),
|
|
this,SLOT(slotCardsMoved(CardMoveRecord)));
|
|
this->connect(this->m_stackVector[i],SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)),
|
|
this,SLOT(slotStackCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)));
|
|
}
|
|
|
|
this->m_pDeck=new CardStack;
|
|
this->m_scene.addItem(this->m_pDeck);
|
|
|
|
this->m_pDeck->setShowRedealCircle();
|
|
|
|
|
|
// if a card is double clicked that means we need to flip over the next set of cards
|
|
this->connect(this->m_pDeck,SIGNAL(cardClicked(CardStack*,uint)),
|
|
this,SLOT(slotFlipCards(CardStack*,uint)));
|
|
|
|
// if there are no cards in the deck and the pad is clicked that means we need
|
|
// to flip the deck back over. If the version of the game is not No redeals.
|
|
this->connect(this->m_pDeck,SIGNAL(padClicked(CardStack*)),
|
|
this,SLOT(slotRedealCards(CardStack*)));
|
|
|
|
this->m_pFlipDeck=new KlondikeFlipStack;
|
|
this->m_scene.addItem(this->m_pFlipDeck);
|
|
|
|
this->connect(this->m_pFlipDeck,SIGNAL(cardsMovedByDragDrop(CardMoveRecord)),
|
|
this,SLOT(slotCardsMoved(CardMoveRecord)));
|
|
this->connect(this->m_pFlipDeck,SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)),
|
|
this,SLOT(slotStackCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)));
|
|
|
|
|
|
|
|
// hook up the animation signal for flipping cards over from the deck to the flip
|
|
// stack. And then back.
|
|
this->connect(&m_sToSFlipAni,SIGNAL(cardsMoved(CardMoveRecord)),
|
|
this,SLOT(slotCardsMoved(CardMoveRecord)));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool KlondikeBoard::isGameWon()const
|
|
{
|
|
bool rc=true;
|
|
|
|
for (unsigned int i=0;i<this->m_homeVector.size();i++)
|
|
{
|
|
if (!this->m_homeVector[i]->isStackComplete())
|
|
{
|
|
rc=false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool KlondikeBoard::isGameWonNotComplete()const
|
|
{
|
|
bool rc=false;
|
|
|
|
rc=m_pDeck->isEmpty();
|
|
|
|
if (rc)
|
|
{
|
|
rc=this->m_pFlipDeck->cardsAscendingTopToBottom();
|
|
}
|
|
|
|
if (rc)
|
|
{
|
|
for (unsigned int i=0;i<this->m_stackVector.size();i++)
|
|
{
|
|
if (!(this->m_stackVector[i]->cardsAscendingTopToBottom() &&
|
|
this->m_stackVector[i]->allCardsFaceUp()))
|
|
{
|
|
rc=false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|