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

0001 /*
0002  * Copyright (C) 1997 Rodolfo Borges <barrett@labma.ufrj.br>
0003  * Copyright (C) 1998-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 "mod3.h"
0039 
0040 // own
0041 #include "dealerinfo.h"
0042 #include "patsolve/mod3solver.h"
0043 // KF
0044 #include <KLocalizedString>
0045 
0046 Mod3::Mod3(const DealerInfo *di)
0047     : DealerScene(di)
0048 {
0049 }
0050 
0051 void Mod3::initialize()
0052 {
0053     // Piles are placed very close together. Set layoutSpacing to 0 to prevent
0054     // interference between them.
0055     setLayoutSpacing(0.0);
0056 
0057     const qreal dist_x = 1.114;
0058     const qreal dist_y = 1.31;
0059     const qreal bottomRowY = 3 * dist_y + 0.2;
0060     const qreal rightColumX = 8 * dist_x + 0.8;
0061 
0062     // This patience uses 2 deck of cards.
0063     setDeckContents(2);
0064 
0065     talon = new PatPile(this, 0, QStringLiteral("talon"));
0066     talon->setPileRole(PatPile::Stock);
0067     talon->setLayoutPos(rightColumX, bottomRowY);
0068     talon->setSpread(0, 0);
0069     talon->setKeyboardSelectHint(KCardPile::NeverFocus);
0070     talon->setKeyboardDropHint(KCardPile::NeverFocus);
0071     connect(talon, &KCardPile::clicked, this, &DealerScene::drawDealRowOrRedeal);
0072 
0073     aces = new PatPile(this, 50, QStringLiteral("aces"));
0074     aces->setPileRole(PatPile::FoundationType1);
0075     aces->setLayoutPos(rightColumX, 0.5);
0076     aces->setBottomPadding(2.5);
0077     aces->setKeyboardSelectHint(KCardPile::NeverFocus);
0078     aces->setKeyboardDropHint(KCardPile::ForceFocusTop);
0079 
0080     for (int r = 0; r < 4; ++r) {
0081         for (int c = 0; c < 8; ++c) {
0082             int pileIndex = r * 10 + c + 1;
0083             QString objectName = QStringLiteral("stack%1_%2").arg(r).arg(c);
0084             stack[r][c] = new PatPile(this, pileIndex, objectName);
0085 
0086             // The first 3 rows are the playing field, the fourth is the store.
0087             if (r < 3) {
0088                 stack[r][c]->setLayoutPos(dist_x * c, dist_y * r);
0089                 // Very tight spread makes it easy to quickly tell number of
0090                 // cards in each pile and we don't care about the cards beneath.
0091                 stack[r][c]->setSpread(0, 0.08);
0092                 stack[r][c]->setBottomPadding(0.23);
0093             } else {
0094                 stack[r][c]->setLayoutPos(dist_x * c, bottomRowY);
0095                 stack[r][c]->setBottomPadding(0.8);
0096             }
0097             stack[r][c]->setPileRole(r == 0       ? PatPile::FoundationType2
0098                                          : r == 1 ? PatPile::FoundationType3
0099                                          : r == 2 ? PatPile::FoundationType4
0100                                                   : PatPile::Tableau);
0101             stack[r][c]->setHeightPolicy(KCardPile::GrowDown);
0102             stack[r][c]->setKeyboardSelectHint(KCardPile::AutoFocusTop);
0103             stack[r][c]->setKeyboardDropHint(KCardPile::AutoFocusTop);
0104         }
0105     }
0106 
0107     setActions(DealerScene::Hint | DealerScene::Demo | DealerScene::Deal);
0108     setSolver(new Mod3Solver(this));
0109 }
0110 
0111 bool mod3CheckAdd(int baseRank, const QList<KCard *> &oldCards, const QList<KCard *> &newCards)
0112 {
0113     if (oldCards.isEmpty())
0114         return newCards.first()->rank() == baseRank;
0115     else
0116         return oldCards.first()->rank() == baseRank && newCards.first()->suit() == oldCards.last()->suit()
0117             && newCards.first()->rank() == oldCards.last()->rank() + 3;
0118 }
0119 
0120 bool Mod3::checkAdd(const PatPile *pile, const QList<KCard *> &oldCards, const QList<KCard *> &newCards) const
0121 {
0122     switch (pile->pileRole()) {
0123     case PatPile::FoundationType1:
0124         return newCards.size() == 1 && newCards.first()->rank() == KCardDeck::Ace;
0125     case PatPile::FoundationType2:
0126         return mod3CheckAdd(KCardDeck::Two, oldCards, newCards);
0127     case PatPile::FoundationType3:
0128         return mod3CheckAdd(KCardDeck::Three, oldCards, newCards);
0129     case PatPile::FoundationType4:
0130         return mod3CheckAdd(KCardDeck::Four, oldCards, newCards);
0131     case PatPile::Tableau:
0132         return oldCards.isEmpty();
0133     case PatPile::Stock:
0134     default:
0135         return false;
0136     }
0137 }
0138 
0139 bool Mod3::checkRemove(const PatPile *pile, const QList<KCard *> &cards) const
0140 {
0141     switch (pile->pileRole()) {
0142     case PatPile::FoundationType2:
0143     case PatPile::FoundationType3:
0144     case PatPile::FoundationType4:
0145     case PatPile::Tableau:
0146         return cards.first() == pile->topCard();
0147     case PatPile::FoundationType1:
0148     case PatPile::Stock:
0149     default:
0150         return false;
0151     }
0152 }
0153 
0154 void Mod3::cardsMoved(const QList<KCard *> &cards, KCardPile *oldPile, KCardPile *newPile)
0155 {
0156     if (oldPile->isEmpty() && !talon->isEmpty()) {
0157         PatPile *p = dynamic_cast<PatPile *>(oldPile);
0158         if (p && p->pileRole() == PatPile::Tableau)
0159             flipCardToPile(talon->topCard(), oldPile, DURATION_MOVE);
0160     }
0161 
0162     DealerScene::cardsMoved(cards, oldPile, newPile);
0163 }
0164 
0165 void Mod3::restart(const QList<KCard *> &cards)
0166 {
0167     for (KCard *c : cards) {
0168         c->setPos(talon->pos());
0169         c->setFaceUp(false);
0170         talon->add(c);
0171     }
0172 
0173     for (int r = 0; r < 4; r++) {
0174         for (int c = 0; c < 8; ++c) {
0175             KCard *card = talon->topCard();
0176             card->setFaceUp(true);
0177             //             moveCardToPileAtSpeed( card, stack[r][c], DEAL_SPEED );
0178 
0179             addCardForDeal(stack[r][c], card, true, talon->pos());
0180 
0181             // Fudge the z values to keep cards from popping through one another.
0182             card->setZValue(card->zValue() + ((4 - r) * (4 - r)) + ((8 - c) * (8 - c)));
0183         }
0184     }
0185 
0186     startDealAnimation();
0187     Q_EMIT newCardsPossible(true);
0188 }
0189 
0190 bool Mod3::newCards()
0191 {
0192     if (talon->isEmpty())
0193         return false;
0194 
0195     for (int c = 0; c < 8; ++c) {
0196         if (talon->isEmpty())
0197             break;
0198 
0199         flipCardToPileAtSpeed(talon->topCard(), stack[3][c], DEAL_SPEED * 2);
0200     }
0201 
0202     if (talon->isEmpty())
0203         Q_EMIT newCardsPossible(false);
0204 
0205     return true;
0206 }
0207 
0208 void Mod3::setGameState(const QString &state)
0209 {
0210     Q_UNUSED(state);
0211     Q_EMIT newCardsPossible(!talon->isEmpty());
0212 }
0213 
0214 static class Mod3DealerInfo : public DealerInfo
0215 {
0216 public:
0217     Mod3DealerInfo()
0218         : DealerInfo(kli18n("Mod3"), Mod3Id)
0219     {
0220     }
0221 
0222     DealerScene *createGame() const override
0223     {
0224         return new Mod3(this);
0225     }
0226 } mod3DealerInfo;
0227 
0228 #include "moc_mod3.cpp"