File indexing completed on 2024-05-12 04:04:49
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"