1/*
2 * Copyright (C) 1995 Paul Olav Tvete <paul@troll.no>
3 * Copyright (C) 2000-2009 Stephan Kulow <coolo@kde.org>
4 * Copyright (C) 2010 Parker Coates <coates@kde.org>
5 *
6 * License of original code:
7 * -------------------------------------------------------------------------
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted,
10 * provided that the above copyright notice appear in all copies and that
11 * both that copyright notice and this permission notice appear in
12 * supporting documentation.
13 *
14 * This file is provided AS IS with no warranties of any kind. The author
15 * shall have no liability with respect to the infringement of copyrights,
16 * trade secrets or any patents by this file or any part thereof. In no
17 * event will the author be liable for any lost revenue or profits or
18 * other special, indirect and consequential damages.
19 * -------------------------------------------------------------------------
20 *
21 * License of modifications/additions made after 2009-01-01:
22 * -------------------------------------------------------------------------
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License as
25 * published by the Free Software Foundation; either version 2 of
26 * the License, or (at your option) any later version.
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35 * -------------------------------------------------------------------------
36 */
37
38#include "idiot.h"
39
40#include "dealerinfo.h"
41#include "patsolve/idiotsolver.h"
42
43#include <KLocale>
44
45
46Idiot::Idiot( const DealerInfo * di )
47 : DealerScene( di )
48{
49}
50
51
52void Idiot::initialize()
53{
54 setSceneAlignment( AlignHCenter | AlignVCenter );
55
56 setDeckContents();
57
58 // Create the talon to the left.
59 talon = new PatPile( this, 0, "talon" );
60 talon->setPileRole(PatPile::Stock);
61 talon->setLayoutPos(0, 0);
62 talon->setSpread(0, 0);
63 talon->setKeyboardSelectHint( KCardPile::NeverFocus );
64 talon->setKeyboardDropHint( KCardPile::NeverFocus );
65 connect( talon, SIGNAL(clicked(KCard*)), this, SLOT(newCards()) );
66
67 const qreal distx = 1.1;
68
69 // Create 4 piles where the cards will be placed during the game.
70 for( int i = 0; i < 4; ++i )
71 {
72 m_play[i] = new PatPile( this, i + 1, QString( "play%1" ).arg( i ));
73 m_play[i]->setPileRole(PatPile::Tableau);
74 m_play[i]->setLayoutPos(1.5 + distx * i, 0);
75 m_play[i]->setBottomPadding( 2 );
76 m_play[i]->setHeightPolicy( KCardPile::GrowDown );
77 m_play[i]->setKeyboardSelectHint( KCardPile::AutoFocusTop );
78 m_play[i]->setKeyboardDropHint( KCardPile::AutoFocusTop );
79 }
80
81 // Create the discard pile to the right
82 m_away = new PatPile( this, 5, "away" );
83 m_away->setPileRole(PatPile::Foundation);
84 m_away->setLayoutPos(1.9 + distx * 4, 0);
85 m_away->setSpread(0, 0);
86 m_away->setKeyboardSelectHint(KCardPile::NeverFocus);
87 m_away->setKeyboardDropHint(KCardPile::ForceFocusTop);
88
89 connect( this, SIGNAL(cardClicked(KCard*)), this, SLOT(tryAutomaticMove(KCard*)) );
90
91 setActions(DealerScene::Hint | DealerScene::Demo | DealerScene::Deal);
92 setSolver( new IdiotSolver(this ) );
93}
94
95
96void Idiot::restart( const QList<KCard*> & cards )
97{
98 foreach ( KCard * c, cards )
99 {
100 c->setPos( talon->pos() );
101 c->setFaceUp( false );
102 talon->add( c );
103 }
104
105 dealRow();
106
107 emit newCardsPossible(true);
108}
109
110
111bool Idiot::drop()
112{
113 return false;
114}
115
116
117bool Idiot::checkAdd(const PatPile * pile, const QList<KCard*> & oldCards, const QList<KCard*> & newCards) const
118{
119 switch ( pile->pileRole() )
120 {
121 case PatPile::Foundation:
122 return newCards.size() == 1 && canMoveAway( newCards.first() );
123 case PatPile::Tableau:
124 return oldCards.isEmpty() && newCards.size() == 1;
125 case PatPile::Stock:
126 default:
127 return false;
128 }
129}
130
131bool Idiot::checkRemove(const PatPile * pile, const QList<KCard*> & cards) const
132{
133 return pile->pileRole() == PatPile::Tableau
134 && cards.first() == pile->topCard()
135 && ( canMoveAway( cards.first() )
136 || m_play[0]->isEmpty()
137 || m_play[1]->isEmpty()
138 || m_play[2]->isEmpty()
139 || m_play[3]->isEmpty() );
140}
141
142bool Idiot::canMoveAway(const KCard * card) const
143{
144 Q_ASSERT( card->pile() != talon );
145 Q_ASSERT( card->pile() != m_away );
146 Q_ASSERT( card == card->pile()->topCard() );
147
148 for ( int i = 0; i < 4; ++i )
149 {
150 KCard * c = m_play[i]->topCard();
151 if ( c
152 && c != card
153 && c->suit() == card->suit()
154 && ( c->rank() == KCardDeck::Ace
155 || ( card->rank() != KCardDeck::Ace
156 && c->rank() > card->rank() ) ) )
157 return true;
158 }
159
160 return false;
161}
162
163
164
165bool Idiot::tryAutomaticMove( KCard * card )
166{
167 if ( !isCardAnimationRunning()
168 && card
169 && card->pile()
170 && card == card->pile()->topCard()
171 && card->pile() != talon
172 && card->pile() != m_away )
173 {
174 KCardPile * destination = 0;
175 if ( canMoveAway( card ) )
176 destination = m_away;
177 else if ( m_play[0]->isEmpty() )
178 destination = m_play[0];
179 else if ( m_play[1]->isEmpty() )
180 destination = m_play[1];
181 else if ( m_play[2]->isEmpty() )
182 destination = m_play[2];
183 else if ( m_play[3]->isEmpty() )
184 destination = m_play[3];
185
186 if ( destination )
187 {
188 moveCardToPile( card, destination, DURATION_MOVE );
189 return true;
190 }
191 }
192 return false;
193}
194
195
196// The game is won when:
197// 1. all cards are dealt.
198// 2. all piles contain exactly one ace.
199// 3. the rest of the cards are thrown away (follows automatically from 1, 2.
200//
201bool Idiot::isGameWon() const
202{
203 // Criterium 1.
204 if (!talon->isEmpty())
205 return false;
206
207 // Criterium 2.
208 for (int i = 0; i < 4; i++) {
209 if (m_play[i]->count() != 1 || m_play[i]->topCard()->rank() != KCardDeck::Ace)
210 return false;
211 }
212
213 return true;
214}
215
216
217// Deal 4 cards face up - one on each pile.
218bool Idiot::newCards()
219{
220 if ( talon->isEmpty() )
221 return false;
222
223 dealRow();
224
225 if ( talon->isEmpty() )
226 emit newCardsPossible( false );
227
228 return true;
229}
230
231
232void Idiot::dealRow()
233{
234 Q_ASSERT(talon->count() >= 4);
235
236 for ( int i = 0; i < 4; ++i )
237 {
238 KCard * c = talon->topCard();
239 flipCardToPileAtSpeed( c, m_play[i], DEAL_SPEED );
240
241 // Fudge the z values so that cards don't appear to pop through one another.
242 c->setZValue( c->zValue() + i );
243 }
244}
245
246
247void Idiot::setGameState( const QString & state )
248{
249 Q_UNUSED( state );
250 emit newCardsPossible( !talon->isEmpty() );
251}
252
253
254
255static class IdiotDealerInfo : public DealerInfo
256{
257public:
258 IdiotDealerInfo()
259 : DealerInfo(I18N_NOOP("Aces Up"), AcesUpId)
260 {}
261
262 virtual DealerScene *createGame() const
263 {
264 return new Idiot( this );
265 }
266} idiotDealerInfo;
267
268
269#include "idiot.moc"
270