1/*
2 * Copyright (C) 2000-2009 Stephan Kulow <coolo@kde.org>
3 * Copyright (C) 2010 Parker Coates <coates@kde.org>
4 *
5 * License of original code:
6 * -------------------------------------------------------------------------
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and that
10 * both that copyright notice and this permission notice appear in
11 * supporting documentation.
12 *
13 * This file is provided AS IS with no warranties of any kind. The author
14 * shall have no liability with respect to the infringement of copyrights,
15 * trade secrets or any patents by this file or any part thereof. In no
16 * event will the author be liable for any lost revenue or profits or
17 * other special, indirect and consequential damages.
18 * -------------------------------------------------------------------------
19 *
20 * License of modifications/additions made after 2009-01-01:
21 * -------------------------------------------------------------------------
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License as
24 * published by the Free Software Foundation; either version 2 of
25 * the License, or (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34 * -------------------------------------------------------------------------
35 */
36
37#include "fortyeight.h"
38
39#include "dealerinfo.h"
40#include "pileutils.h"
41#include "speeds.h"
42#include "patsolve/fortyeightsolver.h"
43
44#include <KLocale>
45
46
47Fortyeight::Fortyeight( const DealerInfo* di )
48 : DealerScene( di )
49{
50}
51
52
53void Fortyeight::initialize()
54{
55 const qreal dist_x = 1.11;
56 const qreal smallNeg = -1e-6;
57
58 setDeckContents( 2 );
59
60 talon = new PatPile( this, 0, "talon" );
61 talon->setPileRole(PatPile::Stock);
62 talon->setLayoutPos( 7 * dist_x, smallNeg );
63 talon->setZValue(20);
64 talon->setSpread(0, 0);
65 talon->setKeyboardSelectHint( KCardPile::NeverFocus );
66 talon->setKeyboardDropHint( KCardPile::NeverFocus );
67 connect( talon, SIGNAL(clicked(KCard*)), SLOT(drawDealRowOrRedeal()) );
68
69 pile = new PatPile( this, 20, "pile" );
70 pile->setPileRole(PatPile::Waste);
71 pile->setLayoutPos( 6 * dist_x, smallNeg );
72 pile->setLeftPadding( 6 * dist_x );
73 pile->setWidthPolicy( KCardPile::GrowLeft );
74 pile->setSpread(-0.21, 0);
75 pile->setKeyboardSelectHint( KCardPile::AutoFocusTop );
76 pile->setKeyboardDropHint( KCardPile::NeverFocus );
77
78 for ( int i = 0; i < 8; ++i )
79 {
80 target[i] = new PatPile( this, 9 + i, QString( "target%1" ).arg( i ) );
81 target[i]->setPileRole(PatPile::Foundation);
82 target[i]->setLayoutPos(dist_x*i, 0);
83 target[i]->setSpread(0, 0);
84 target[i]->setKeyboardSelectHint( KCardPile::NeverFocus );
85 target[i]->setKeyboardDropHint( KCardPile::ForceFocusTop );
86 }
87
88 for ( int i = 0; i < 8; ++i )
89 {
90 stack[i] = new PatPile( this, 1 + i, QString( "stack%1" ).arg( i ) );
91 stack[i]->setPileRole(PatPile::Tableau);
92 stack[i]->setLayoutPos(dist_x*i, 1.1 );
93 stack[i]->setAutoTurnTop(true);
94 stack[i]->setSpread(0, 0.25);
95 stack[i]->setBottomPadding( 1.75 );
96 stack[i]->setHeightPolicy( KCardPile::GrowDown );
97 stack[i]->setKeyboardSelectHint( KCardPile::FreeFocus );
98 stack[i]->setKeyboardDropHint( KCardPile::AutoFocusTop );
99 }
100
101 setActions(DealerScene::Hint | DealerScene::Demo | DealerScene::Draw);
102 setSolver( new FortyeightSolver( this ) );
103}
104
105
106void Fortyeight::restart( const QList<KCard*> & cards )
107{
108 lastdeal = false;
109
110 QList<KCard*> cardList = cards;
111
112 for ( int r = 0; r < 4; ++r )
113 {
114 for ( int column = 0; column < 8; ++column )
115 {
116 QPointF initPos = stack[column]->pos() - QPointF( 0, 2 * deck()->cardHeight() );
117 addCardForDeal( stack[column], cardList.takeLast(), true, initPos );
118 }
119 }
120
121 while ( !cardList.isEmpty() )
122 {
123 KCard * c = cardList.takeFirst();
124 c->setPos( talon->pos() );
125 c->setFaceUp( false );
126 talon->add( c );
127 }
128
129 startDealAnimation();
130
131 flipCardToPile( talon->topCard(), pile, DURATION_MOVE );
132
133 emit newCardsPossible( true );
134}
135
136
137bool Fortyeight::newCards()
138{
139 if ( talon->isEmpty() )
140 {
141 if ( lastdeal )
142 {
143 return false;
144 }
145 else
146 {
147 lastdeal = true;
148 flipCardsToPile( pile->cards(), talon, DURATION_MOVE );
149 }
150 }
151 else
152 {
153 flipCardToPile( talon->topCard(), pile, DURATION_MOVE );
154 setKeyboardFocus( pile->topCard() );
155 }
156
157 if ( talon->isEmpty() && lastdeal )
158 emit newCardsPossible( false );
159
160 return true;
161}
162
163
164void Fortyeight::cardsDroppedOnPile( const QList<KCard*> & cards, KCardPile * pile )
165{
166 if ( cards.size() <= 1 )
167 {
168 DealerScene::moveCardsToPile( cards, pile, DURATION_MOVE );
169 return;
170 }
171
172 QList<KCardPile*> freePiles;
173 for ( int i = 0; i < 8; ++i )
174 if ( stack[i]->isEmpty() && stack[i] != pile )
175 freePiles << stack[i];
176
177 multiStepMove( cards, pile, freePiles, QList<KCardPile*>(), DURATION_MOVE );
178}
179
180
181bool Fortyeight::canPutStore( const KCardPile * pile, const QList<KCard*> &cards ) const
182{
183 int frees = 0;
184 for (int i = 0; i < 8; i++)
185 if (stack[i]->isEmpty()) frees++;
186
187 if ( pile->isEmpty()) // destination is empty
188 frees--;
189
190 if (int( cards.count()) > 1<<frees)
191 return false;
192
193 // ok if the target is empty
194 if ( pile->isEmpty())
195 return true;
196
197 KCard *c = cards.first(); // we assume there are only valid sequences
198
199 return pile->topCard()->suit() == c->suit()
200 && pile->topCard()->rank() == c->rank() + 1;
201}
202
203bool Fortyeight::checkAdd(const PatPile * pile, const QList<KCard*> & oldCards, const QList<KCard*> & newCards) const
204{
205 switch ( pile->pileRole() )
206 {
207 case PatPile::Foundation:
208 return checkAddSameSuitAscendingFromAce(oldCards, newCards);
209 case PatPile::Tableau:
210 return canPutStore(pile, newCards);
211 case PatPile::Stock:
212 case PatPile::Waste:
213 default:
214 return false;
215 }
216}
217
218
219bool Fortyeight::checkRemove( const PatPile * pile, const QList<KCard*> & cards) const
220{
221 switch ( pile->pileRole() )
222 {
223 case PatPile::Waste:
224 return cards.first() == pile->topCard();
225 case PatPile::Tableau:
226 return isSameSuitDescending(cards);
227 case PatPile::Foundation:
228 case PatPile::Stock:
229 default:
230 return false;
231 }
232}
233
234
235QString Fortyeight::getGameState() const
236{
237 return QString::number(lastdeal);
238}
239
240
241void Fortyeight::setGameState( const QString & state )
242{
243 lastdeal = state.toInt();
244 emit newCardsPossible( !lastdeal || !talon->isEmpty() );
245}
246
247
248static class FortyEightDealerInfo : public DealerInfo
249{
250public:
251 FortyEightDealerInfo()
252 : DealerInfo(I18N_NOOP("Forty & Eight"), FortyAndEightId)
253 {}
254
255 virtual DealerScene *createGame() const
256 {
257 return new Fortyeight( this );
258 }
259} fortyEightDealerInfo;
260
261
262#include "fortyeight.moc"
263