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 "idiot.h"
0039 
0040 // own
0041 #include "dealerinfo.h"
0042 #include "patsolve/idiotsolver.h"
0043 // KF
0044 #include <KLocalizedString>
0045 
0046 Idiot::Idiot(const DealerInfo *di)
0047     : DealerScene(di)
0048 {
0049 }
0050 
0051 void Idiot::initialize()
0052 {
0053     setSceneAlignment(AlignHCenter | AlignVCenter);
0054 
0055     setDeckContents();
0056 
0057     // Create the talon to the left.
0058     talon = new PatPile(this, 0, QStringLiteral("talon"));
0059     talon->setPileRole(PatPile::Stock);
0060     talon->setLayoutPos(0, 0);
0061     talon->setSpread(0, 0);
0062     talon->setKeyboardSelectHint(KCardPile::NeverFocus);
0063     talon->setKeyboardDropHint(KCardPile::NeverFocus);
0064     connect(talon, &PatPile::clicked, this, &Idiot::newCards);
0065 
0066     const qreal distx = 1.1;
0067 
0068     // Create 4 piles where the cards will be placed during the game.
0069     for (int i = 0; i < 4; ++i) {
0070         m_play[i] = new PatPile(this, i + 1, QStringLiteral("play%1").arg(i));
0071         m_play[i]->setPileRole(PatPile::Tableau);
0072         m_play[i]->setLayoutPos(1.5 + distx * i, 0);
0073         m_play[i]->setBottomPadding(2);
0074         m_play[i]->setHeightPolicy(KCardPile::GrowDown);
0075         m_play[i]->setKeyboardSelectHint(KCardPile::AutoFocusTop);
0076         m_play[i]->setKeyboardDropHint(KCardPile::AutoFocusTop);
0077     }
0078 
0079     // Create the discard pile to the right
0080     m_away = new PatPile(this, 5, QStringLiteral("away"));
0081     m_away->setPileRole(PatPile::Foundation);
0082     m_away->setLayoutPos(1.9 + distx * 4, 0);
0083     m_away->setSpread(0, 0);
0084     m_away->setKeyboardSelectHint(KCardPile::NeverFocus);
0085     m_away->setKeyboardDropHint(KCardPile::ForceFocusTop);
0086 
0087     connect(this, &Idiot::cardClicked, this, &Idiot::tryAutomaticMove);
0088 
0089     setActions(DealerScene::Hint | DealerScene::Demo | DealerScene::Deal);
0090     setSolver(new IdiotSolver(this));
0091 }
0092 
0093 void Idiot::restart(const QList<KCard *> &cards)
0094 {
0095     for (KCard *c : cards) {
0096         c->setPos(talon->pos());
0097         c->setFaceUp(false);
0098         talon->add(c);
0099     }
0100 
0101     dealRow();
0102 
0103     Q_EMIT newCardsPossible(true);
0104 }
0105 
0106 bool Idiot::drop()
0107 {
0108     return false;
0109 }
0110 
0111 bool Idiot::checkAdd(const PatPile *pile, const QList<KCard *> &oldCards, const QList<KCard *> &newCards) const
0112 {
0113     switch (pile->pileRole()) {
0114     case PatPile::Foundation:
0115         return newCards.size() == 1 && canMoveAway(newCards.first());
0116     case PatPile::Tableau:
0117         return oldCards.isEmpty() && newCards.size() == 1;
0118     case PatPile::Stock:
0119     default:
0120         return false;
0121     }
0122 }
0123 
0124 bool Idiot::checkRemove(const PatPile *pile, const QList<KCard *> &cards) const
0125 {
0126     return pile->pileRole() == PatPile::Tableau && cards.first() == pile->topCard()
0127         && (canMoveAway(cards.first()) || m_play[0]->isEmpty() || m_play[1]->isEmpty() || m_play[2]->isEmpty() || m_play[3]->isEmpty());
0128 }
0129 
0130 bool Idiot::canMoveAway(const KCard *card) const
0131 {
0132     Q_ASSERT(card->pile() != talon);
0133     Q_ASSERT(card->pile() != m_away);
0134     Q_ASSERT(card == card->pile()->topCard());
0135 
0136     for (int i = 0; i < 4; ++i) {
0137         KCard *c = m_play[i]->topCard();
0138         if (c && c != card && c->suit() == card->suit() && (c->rank() == KCardDeck::Ace || (card->rank() != KCardDeck::Ace && c->rank() > card->rank())))
0139             return true;
0140     }
0141 
0142     return false;
0143 }
0144 
0145 bool Idiot::tryAutomaticMove(KCard *card)
0146 {
0147     if (!isCardAnimationRunning() && card && card->pile() && card == card->pile()->topCard() && card->pile() != talon && card->pile() != m_away) {
0148         KCardPile *destination = nullptr;
0149         if (canMoveAway(card))
0150             destination = m_away;
0151         else if (m_play[0]->isEmpty())
0152             destination = m_play[0];
0153         else if (m_play[1]->isEmpty())
0154             destination = m_play[1];
0155         else if (m_play[2]->isEmpty())
0156             destination = m_play[2];
0157         else if (m_play[3]->isEmpty())
0158             destination = m_play[3];
0159 
0160         if (destination) {
0161             moveCardToPile(card, destination, DURATION_MOVE);
0162             return true;
0163         }
0164     }
0165     return false;
0166 }
0167 
0168 // The game is won when:
0169 //  1. all cards are dealt.
0170 //  2. all piles contain exactly one ace.
0171 //  3. the rest of the cards are thrown away (follows automatically from 1, 2.
0172 //
0173 bool Idiot::isGameWon() const
0174 {
0175     // Criterium 1.
0176     if (!talon->isEmpty())
0177         return false;
0178 
0179     // Criterium 2.
0180     for (int i = 0; i < 4; i++) {
0181         if (m_play[i]->count() != 1 || m_play[i]->topCard()->rank() != KCardDeck::Ace)
0182             return false;
0183     }
0184 
0185     return true;
0186 }
0187 
0188 // Deal 4 cards face up - one on each pile.
0189 bool Idiot::newCards()
0190 {
0191     if (talon->isEmpty())
0192         return false;
0193 
0194     dealRow();
0195 
0196     if (talon->isEmpty())
0197         Q_EMIT newCardsPossible(false);
0198 
0199     return true;
0200 }
0201 
0202 void Idiot::dealRow()
0203 {
0204     Q_ASSERT(talon->count() >= 4);
0205 
0206     for (int i = 0; i < 4; ++i) {
0207         KCard *c = talon->topCard();
0208         flipCardToPileAtSpeed(c, m_play[i], DEAL_SPEED);
0209 
0210         // Fudge the z values so that cards don't appear to pop through one another.
0211         c->setZValue(c->zValue() + i);
0212     }
0213 }
0214 
0215 void Idiot::setGameState(const QString &state)
0216 {
0217     Q_UNUSED(state);
0218     Q_EMIT newCardsPossible(!talon->isEmpty());
0219 }
0220 
0221 static class IdiotDealerInfo : public DealerInfo
0222 {
0223 public:
0224     IdiotDealerInfo()
0225         : DealerInfo(kli18n("Aces Up"), AcesUpId)
0226     {
0227     }
0228 
0229     DealerScene *createGame() const override
0230     {
0231         return new Idiot(this);
0232     }
0233 } idiotDealerInfo;
0234 
0235 #include "moc_idiot.cpp"