File indexing completed on 2024-05-12 08:00:33

0001 /*
0002  * Copyright (C) 1995 Paul Olav Tvete <paul@troll.no>
0003  * Copyright (C) 2000-2009 Stephan Kulow <coolo@kde.org>
0004  * Copyright (C) 2010 Parker Coates <coates@kde.org>
0005  *
0006  * License of original code:
0007  * -------------------------------------------------------------------------
0008  *   Permission to use, copy, modify, and distribute this software and its
0009  *   documentation for any purpose and without fee is hereby granted,
0010  *   provided that the above copyright notice appear in all copies and that
0011  *   both that copyright notice and this permission notice appear in
0012  *   supporting documentation.
0013  *
0014  *   This file is provided AS IS with no warranties of any kind.  The author
0015  *   shall have no liability with respect to the infringement of copyrights,
0016  *   trade secrets or any patents by this file or any part thereof.  In no
0017  *   event will the author be liable for any lost revenue or profits or
0018  *   other special, indirect and consequential damages.
0019  * -------------------------------------------------------------------------
0020  *
0021  * License of modifications/additions made after 2009-01-01:
0022  * -------------------------------------------------------------------------
0023  *   This program is free software; you can redistribute it and/or
0024  *   modify it under the terms of the GNU General Public License as
0025  *   published by the Free Software Foundation; either version 2 of
0026  *   the License, or (at your option) any later version.
0027  *
0028  *   This program is distributed in the hope that it will be useful,
0029  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0030  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0031  *   GNU General Public License for more details.
0032  *
0033  *   You should have received a copy of the GNU General Public License
0034  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
0035  * -------------------------------------------------------------------------
0036  */
0037 
0038 #include "grandf.h"
0039 
0040 // own
0041 #include "dealerinfo.h"
0042 #include "patsolve/grandfsolver.h"
0043 #include "pileutils.h"
0044 #include "speeds.h"
0045 // KF
0046 #include <KLocalizedString>
0047 
0048 Grandf::Grandf(const DealerInfo *di)
0049     : DealerScene(di)
0050 {
0051 }
0052 
0053 void Grandf::initialize()
0054 {
0055     setDeckContents();
0056 
0057     const qreal distx = 1.4;
0058     const qreal targetOffset = 1.5 * distx;
0059 
0060     for (int i = 0; i < 4; ++i) {
0061         target[i] = new PatPile(this, i + 1, QStringLiteral("target%1").arg(i));
0062         target[i]->setPileRole(PatPile::Foundation);
0063         target[i]->setLayoutPos(targetOffset + i * distx, 0);
0064         target[i]->setSpread(0, 0);
0065         target[i]->setKeyboardSelectHint(KCardPile::NeverFocus);
0066         target[i]->setKeyboardDropHint(KCardPile::ForceFocusTop);
0067     }
0068 
0069     for (int i = 0; i < 7; ++i) {
0070         store[i] = new PatPile(this, 5 + i, QStringLiteral("store%1").arg(i));
0071         store[i]->setPileRole(PatPile::Tableau);
0072         store[i]->setLayoutPos(distx * i, 1.2);
0073         store[i]->setAutoTurnTop(true);
0074         store[i]->setBottomPadding(2.5);
0075         store[i]->setHeightPolicy(KCardPile::GrowDown);
0076         store[i]->setKeyboardSelectHint(KCardPile::FreeFocus);
0077         store[i]->setKeyboardDropHint(KCardPile::AutoFocusTop);
0078     }
0079 
0080     setActions(DealerScene::Hint | DealerScene::Demo | DealerScene::Redeal);
0081     setSolver(new GrandfSolver(this));
0082 }
0083 
0084 void Grandf::restart(const QList<KCard *> &cards)
0085 {
0086     deal(cards);
0087     numberOfDeals = 1;
0088     Q_EMIT newCardsPossible(true);
0089 }
0090 
0091 bool Grandf::newCards()
0092 {
0093     if (numberOfDeals >= 3)
0094         return false;
0095 
0096     // NOTE: This is not quite correct. The piles should be turned face down
0097     //       (i.e. partially reversed) during collection.
0098     QList<KCard *> collectedCards;
0099     for (int pos = 6; pos >= 0; --pos) {
0100         collectedCards << store[pos]->cards();
0101         store[pos]->clear();
0102     }
0103     deal(collectedCards);
0104     takeState();
0105 
0106     numberOfDeals++;
0107 
0108     if (numberOfDeals == 3)
0109         Q_EMIT newCardsPossible(false);
0110 
0111     return true;
0112 }
0113 
0114 void Grandf::deal(const QList<KCard *> &cardsToDeal)
0115 {
0116     setKeyboardModeActive(false);
0117 
0118     QList<KCard *> cards = cardsToDeal;
0119 
0120     QPointF initPos(1.4 * 3 * deck()->cardWidth(), 1.2 * deck()->cardHeight());
0121 
0122     int start = 0;
0123     int stop = 7 - 1;
0124     int dir = 1;
0125 
0126     for (int round = 0; round < 7; round++) {
0127         int i = start;
0128         do {
0129             if (!cards.isEmpty())
0130                 addCardForDeal(store[i], cards.takeLast(), (i == start), initPos);
0131             i += dir;
0132         } while (i != stop + dir);
0133         int t = start;
0134         start = stop;
0135         stop = t + dir;
0136         dir = -dir;
0137     }
0138 
0139     int i = 0;
0140     while (!cards.isEmpty()) {
0141         addCardForDeal(store[i + 1], cards.takeLast(), true, initPos);
0142         i = (i + 1) % 6;
0143     }
0144 
0145     for (int round = 0; round < 7; round++) {
0146         KCard *c = store[round]->topCard();
0147         if (c)
0148             c->setFaceUp(true);
0149     }
0150 
0151     startDealAnimation();
0152 }
0153 
0154 bool Grandf::checkAdd(const PatPile *pile, const QList<KCard *> &oldCards, const QList<KCard *> &newCards) const
0155 {
0156     switch (pile->pileRole()) {
0157     case PatPile::Tableau:
0158         if (oldCards.isEmpty())
0159             return newCards.first()->rank() == KCardDeck::King;
0160         else
0161             return newCards.first()->rank() == oldCards.last()->rank() - 1 && newCards.first()->suit() == oldCards.last()->suit();
0162     case PatPile::Foundation:
0163     default:
0164         return checkAddSameSuitAscendingFromAce(oldCards, newCards);
0165     }
0166 }
0167 
0168 bool Grandf::checkRemove(const PatPile *pile, const QList<KCard *> &cards) const
0169 {
0170     return pile->pileRole() == PatPile::Tableau && cards.first()->isFaceUp();
0171 }
0172 
0173 QString Grandf::getGameState() const
0174 {
0175     return QString::number(numberOfDeals);
0176 }
0177 
0178 void Grandf::setGameState(const QString &state)
0179 {
0180     numberOfDeals = state.toInt();
0181     Q_EMIT newCardsPossible(numberOfDeals < 3);
0182 }
0183 
0184 static class GrandfDealerInfo : public DealerInfo
0185 {
0186 public:
0187     GrandfDealerInfo()
0188         : DealerInfo(kli18n("Grandfather"), GrandfatherId)
0189     {
0190     }
0191 
0192     DealerScene *createGame() const override
0193     {
0194         return new Grandf(this);
0195     }
0196 } grandfDealerInfo;
0197 
0198 #include "moc_grandf.cpp"