/* 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 . */ #include "YukonBoard.h" #include "CardPixmaps.h" #include ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// YukonBoard::YukonBoard() :GameBoard(NULL,QString(tr("Yukon Solitaire")).trimmed(),QString("Yukon")), m_pDeck(NULL), m_homeVector(), m_stackVector(), m_cheat(false) { this->setHelpFile(":/help/YukonHelp.html"); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// YukonBoard::~YukonBoard() { } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// bool YukonBoard::getHint(CardStack * & pSrc, unsigned int & srcStackIndex, CardStack * & pDst) { bool rc=false; unsigned int i; // ok we will look for a move based on trying to move the first faceup // card in a stack. The basic strategy for this game is to get all cards turned // over. if (!rc) { for (i=0;im_stackVector.size() && !rc;i++) { unsigned int j; for (j=0;jm_stackVector.size() && !rc;j++) { // can't move a stack to itself if (i!=j) { PlayingCardVector addCardVector(this->m_stackVector[j]->getCardVector()); unsigned int k=0; while (!rc && addCardVector.size()>0) { // ok find the first card that is faceup. if (!addCardVector[0].isFaceUp()) { addCardVector.erase(addCardVector.begin()); } // no need to do this if a king is already face up and the first card in the stack. else if (!(PlayingCard::King==addCardVector[0].getIndex() && 0==k && this->m_stackVector[i]->isEmpty()) && this->m_stackVector[i]->canAddCards(addCardVector)) { pDst=this->m_stackVector[i]; srcStackIndex=k; pSrc=this->m_stackVector[j]; rc=true; } else { break; } k++; } } } } } // ok let's see if we have an empty stack // and a face up king. if (!rc) { CardStack * pEmptyStack=NULL; CardStack * pFaceUpKingStack=NULL; unsigned int faceUpKingIndex=0; for (i=0;im_stackVector.size() && !rc;i++) { if (NULL==pEmptyStack && this->m_stackVector[i]->isEmpty()) { pEmptyStack=this->m_stackVector[i]; } if (NULL==pFaceUpKingStack) { const PlayingCardVector cardVector=this->m_stackVector[i]->getCardVector(); unsigned int j; for(j=0;jm_homeVector.size() && !rc;i++) { unsigned int j; for (j=0;jm_stackVector.size() && !rc;j++) { const PlayingCardVector cardVector=this->m_stackVector[j]->getCardVector(); if (cardVector.size()>0) { PlayingCardVector addCardVector; addCardVector.push_back(cardVector[cardVector.size()-1]); if (this->m_homeVector[i]->canAddCards(addCardVector)) { pDst=this->m_homeVector[i]; srcStackIndex=cardVector.size()-1; pSrc=this->m_stackVector[j]; rc=true; } } } } } // look at each stack and try to find the first available card that from another // stack that can be moved to the stack. if (!rc) { for (i=0;im_stackVector.size() && !rc;i++) { unsigned int j; for (j=0;jm_stackVector.size() && !rc;j++) { // can't move a stack to itself if (i!=j) { PlayingCardVector addCardVector(this->m_stackVector[j]->getCardVector()); unsigned int k=0; while (!rc && addCardVector.size()>0) { // ok find the first card that is faceup. if (!addCardVector[0].isFaceUp()) { addCardVector.erase(addCardVector.begin()); } else if (this->m_stackVector[i]->canAddCards(addCardVector)) { pDst=this->m_stackVector[i]; srcStackIndex=k; pSrc=this->m_stackVector[j]; rc=true; } else { addCardVector.erase(addCardVector.begin()); } k++; } } } } } return rc; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void YukonBoard::newGame() { // call the base class GameBoard::newGame(); CardDeck deck; unsigned int i; 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;im_stackVector.size();i++) { dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck)); unsigned int j; for (j=0;j0) { for (j=0;j<4;j++) { dealItemVector[i].addCard(true); } } } // ok now start the deal. We don't need a move record for this item. m_dealAni.dealCards(dealItemVector,false); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void YukonBoard::addGameMenuItems(QMenu & menu) { Q_UNUSED(menu); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void YukonBoard::loadSettings(const QSettings & settings) { Q_UNUSED(settings); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void YukonBoard::saveSettings(QSettings & settings) { Q_UNUSED(settings); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void YukonBoard::setCheat(bool cheat) { this->m_cheat=cheat; for(unsigned int i=0;im_stackVector.size();i++) { m_stackVector[i]->setCheat(cheat); } } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void YukonBoard::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;im_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. if (NULL==pFoundStack) { for(i=0;im_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 YukonBoard::calcScore() { int score=0; for(unsigned int i=0;im_homeVector.size();i++) { score+=this->m_homeVector[i]->score(); } emit scoreChanged(score,""); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void YukonBoard::resizeEvent (QResizeEvent * event) { int i; this->setCardResizeAlg(8,ResizeByWidth); GameBoard::resizeEvent(event); QSize cardSize(CardPixmaps::getInst().getCardSize()); // ok let's see if it fits when we size things by width // basically we just need to check if we have room to draw // 4 cards vertically. If we don't have enough room we // will try to draw by height. if (cardSize.height()*4+GameBoard::LayoutSpacing*5>event->size().height()) { this->setCardResizeAlg(4,ResizeByHeight); GameBoard::resizeEvent(event); cardSize=CardPixmaps::getInst().getCardSize(); } QPointF currPos(GameBoard::LayoutSpacing,GameBoard::LayoutSpacing); for (i=0;i(m_homeVector.size());i++) { m_homeVector[i]->setPos(currPos); currPos.ry()+=GameBoard::LayoutSpacing+cardSize.height(); } currPos.setX(event->size().width()-GameBoard::LayoutSpacing-cardSize.width()); currPos.setY(GameBoard::LayoutSpacing); for (i=m_stackVector.size()-1;i>=0;i--) { m_stackVector[i]->setPos(currPos); currPos.rx()-=cardSize.width()+GameBoard::LayoutSpacing; } currPos.setX(GameBoard::LayoutSpacing*4+cardSize.width()*4); currPos.setY(event->size().height()-GameBoard::LayoutSpacing-cardSize.height()); m_pDeck->setPos(currPos); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void YukonBoard::createStacks() { 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 FreeCellHome); this->m_scene.addItem(m_homeVector[i]); } // 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 FreeCellDeck; this->m_scene.addItem(this->m_pDeck); } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// bool YukonBoard::isGameWon()const { bool rc=true; for (unsigned int i=0;im_homeVector.size();i++) { if (!this->m_homeVector[i]->isStackComplete()) { rc=false; break; } } return rc; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// bool YukonBoard::isGameWonNotComplete()const { bool rc=true; for (unsigned int i=0;im_stackVector.size();i++) { if (!(this->m_stackVector[i]->cardsAscendingTopToBottom() && this->m_stackVector[i]->allCardsFaceUp())) { rc=false; break; } } return rc; }