1/*
2 * Copyright (C) 1997 Rodolfo Borges <barrett@labma.ufrj.br>
3 * Copyright (C) 1998-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 "mod3.h"
39
40#include "dealerinfo.h"
41#include "patsolve/mod3solver.h"
42
43#include <KLocale>
44
45
46Mod3::Mod3( const DealerInfo * di )
47 : DealerScene( di )
48{
49}
50
51
52void Mod3::initialize()
53{
54 // Piles are placed very close together. Set layoutSpacing to 0 to prevent
55 // interference between them.
56 setLayoutSpacing(0.0);
57
58 const qreal dist_x = 1.114;
59 const qreal dist_y = 1.31;
60 const qreal bottomRowY = 3 * dist_y + 0.2;
61 const qreal rightColumX = 8 * dist_x + 0.8;
62
63 // This patience uses 2 deck of cards.
64 setDeckContents( 2 );
65
66 talon = new PatPile( this, 0, "talon" );
67 talon->setPileRole(PatPile::Stock);
68 talon->setLayoutPos(rightColumX, bottomRowY);
69 talon->setSpread(0, 0);
70 talon->setKeyboardSelectHint( KCardPile::NeverFocus );
71 talon->setKeyboardDropHint( KCardPile::NeverFocus );
72 connect( talon, SIGNAL(clicked(KCard*)), SLOT(drawDealRowOrRedeal()) );
73
74 aces = new PatPile( this, 50, "aces");
75 aces->setPileRole(PatPile::FoundationType1);
76 aces->setLayoutPos(rightColumX, 0.5);
77 aces->setBottomPadding( 2.5 );
78 aces->setKeyboardSelectHint( KCardPile::NeverFocus );
79 aces->setKeyboardDropHint( KCardPile::ForceFocusTop );
80
81 for ( int r = 0; r < 4; ++r )
82 {
83 for ( int c = 0; c < 8; ++c )
84 {
85 int pileIndex = r * 10 + c + 1;
86 QString objectName = QString( "stack%1_%2" ).arg( r ).arg( c );
87 stack[r][c] = new PatPile( this, pileIndex, objectName );
88
89 // The first 3 rows are the playing field, the fourth is the store.
90 if ( r < 3 )
91 {
92 stack[r][c]->setLayoutPos( dist_x * c, dist_y * r );
93 // Very tight spread makes it easy to quickly tell number of
94 // cards in each pile and we don't care about the cards beneath.
95 stack[r][c]->setSpread( 0, 0.08 );
96 stack[r][c]->setBottomPadding( 0.23 );
97 }
98 else
99 {
100 stack[r][c]->setLayoutPos( dist_x * c, bottomRowY );
101 stack[r][c]->setBottomPadding( 0.8 );
102 }
103 stack[r][c]->setPileRole( r == 0 ? PatPile::FoundationType2
104 : r == 1 ? PatPile::FoundationType3
105 : r == 2 ? PatPile::FoundationType4
106 : PatPile::Tableau );
107 stack[r][c]->setHeightPolicy( KCardPile::GrowDown );
108 stack[r][c]->setKeyboardSelectHint( KCardPile::AutoFocusTop );
109 stack[r][c]->setKeyboardDropHint( KCardPile::AutoFocusTop );
110 }
111 }
112
113 setActions(DealerScene::Hint | DealerScene::Demo | DealerScene::Deal);
114 setSolver( new Mod3Solver( this ) );
115}
116
117bool mod3CheckAdd(int baseRank, const QList<KCard*> & oldCards, const QList<KCard*> & newCards)
118{
119 if (oldCards.isEmpty())
120 return newCards.first()->rank() == baseRank;
121 else
122 return oldCards.first()->rank() == baseRank
123 && newCards.first()->suit() == oldCards.last()->suit()
124 && newCards.first()->rank() == oldCards.last()->rank() + 3;
125}
126
127bool Mod3::checkAdd(const PatPile * pile, const QList<KCard*> & oldCards, const QList<KCard*> & newCards) const
128{
129 switch (pile->pileRole())
130 {
131 case PatPile::FoundationType1:
132 return newCards.size() == 1 && newCards.first()->rank() == KCardDeck::Ace;
133 case PatPile::FoundationType2:
134 return mod3CheckAdd(KCardDeck::Two, oldCards, newCards);
135 case PatPile::FoundationType3:
136 return mod3CheckAdd(KCardDeck::Three, oldCards, newCards);
137 case PatPile::FoundationType4:
138 return mod3CheckAdd(KCardDeck::Four, oldCards, newCards);
139 case PatPile::Tableau:
140 return oldCards.isEmpty();
141 case PatPile::Stock:
142 default:
143 return false;
144 }
145}
146
147bool Mod3::checkRemove(const PatPile * pile, const QList<KCard*> & cards) const
148{
149 switch (pile->pileRole())
150 {
151 case PatPile::FoundationType2:
152 case PatPile::FoundationType3:
153 case PatPile::FoundationType4:
154 case PatPile::Tableau:
155 return cards.first() == pile->topCard();
156 case PatPile::FoundationType1:
157 case PatPile::Stock:
158 default:
159 return false;
160 }
161}
162
163
164void Mod3::cardsMoved( const QList<KCard*> & cards, KCardPile * oldPile, KCardPile * newPile )
165{
166 if ( oldPile->isEmpty() && !talon->isEmpty() )
167 {
168 PatPile * p = dynamic_cast<PatPile*>( oldPile );
169 if ( p && p->pileRole() == PatPile::Tableau )
170 flipCardToPile( talon->topCard(), oldPile, DURATION_MOVE );
171 }
172
173 DealerScene::cardsMoved( cards, oldPile, newPile );
174}
175
176
177void Mod3::restart( const QList<KCard*> & cards )
178{
179 foreach ( KCard * c, cards )
180 {
181 c->setPos( talon->pos() );
182 c->setFaceUp( false );
183 talon->add( c );
184 }
185
186 for ( int r = 0; r < 4; r++ )
187 {
188 for ( int c = 0; c < 8; ++c )
189 {
190 KCard * card = talon->topCard();
191 card->setFaceUp( true );
192// moveCardToPileAtSpeed( card, stack[r][c], DEAL_SPEED );
193
194 addCardForDeal( stack[r][c], card, true, talon->pos() );
195
196 // Fudge the z values to keep cards from popping through one another.
197 card->setZValue( card->zValue() + ((4 - r) * (4 - r)) + ((8 - c) * (8 - c)) );
198 }
199 }
200
201 startDealAnimation();
202 emit newCardsPossible(true);
203}
204
205
206bool Mod3::newCards()
207{
208 if ( talon->isEmpty() )
209 return false;
210
211 for ( int c = 0; c < 8; ++c )
212 {
213 if ( talon->isEmpty() )
214 break;
215
216 flipCardToPileAtSpeed( talon->topCard(), stack[3][c], DEAL_SPEED * 2 );
217 }
218
219 if (talon->isEmpty())
220 emit newCardsPossible(false);
221
222 return true;
223}
224
225
226void Mod3::setGameState( const QString & state )
227{
228 Q_UNUSED( state );
229 emit newCardsPossible(!talon->isEmpty());
230}
231
232
233
234static class Mod3DealerInfo : public DealerInfo
235{
236public:
237 Mod3DealerInfo()
238 : DealerInfo(I18N_NOOP("Mod3"), Mod3Id)
239 {}
240
241 virtual DealerScene *createGame() const
242 {
243 return new Mod3( this );
244 }
245} mod3DealerInfo;
246
247
248#include "mod3.moc"
249