diff --git a/freecell.cpp b/freecell.cpp index ecc197a..1581c5a 100644 --- a/freecell.cpp +++ b/freecell.cpp @@ -1,309 +1,304 @@ /* * Copyright (C) 1997 Rodolfo Borges * Copyright (C) 1998-2009 Stephan Kulow * Copyright (C) 2010 Parker Coates * * License of original code: * ------------------------------------------------------------------------- * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * ------------------------------------------------------------------------- * * License of modifications/additions made after 2009-01-01: * ------------------------------------------------------------------------- * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ------------------------------------------------------------------------- */ #include "freecell.h" #include "dealerinfo.h" #include "kpat_debug.h" #include "pileutils.h" #include "speeds.h" #include "patsolve/freecellsolver.h" #include Freecell::Freecell( const DealerInfo * di ) : DealerScene( di ) { } void Freecell::initialize() { setDeckContents(); const qreal topRowDist = 1.08; const qreal bottomRowDist = 1.13; const qreal targetOffsetDist = ( 7 * bottomRowDist + 1 ) - ( 3 * topRowDist + 1 ); for ( int i = 0; i < 4; ++i ) { freecell[i] = new PatPile ( this, 1 + 8 + i, QStringLiteral( "freecell%1" ).arg( i ) ); freecell[i]->setPileRole(PatPile::Cell); freecell[i]->setLayoutPos(topRowDist * i, 0); freecell[i]->setKeyboardSelectHint( KCardPile::AutoFocusTop ); freecell[i]->setKeyboardDropHint( KCardPile::AutoFocusTop ); } for ( int i = 0; i < 8; ++i ) { store[i] = new PatPile( this, 1 + i, QStringLiteral( "store%1" ).arg( i ) ); store[i]->setPileRole(PatPile::Tableau); store[i]->setLayoutPos( bottomRowDist * i, 1.3 ); store[i]->setBottomPadding( 2.5 ); store[i]->setHeightPolicy( KCardPile::GrowDown ); store[i]->setKeyboardSelectHint( KCardPile::AutoFocusDeepestRemovable ); store[i]->setKeyboardDropHint( KCardPile::AutoFocusTop ); } for ( int i = 0; i < 4; ++i ) { target[i] = new PatPile(this, 1 + 8 + 4 + i, QStringLiteral( "target%1" ).arg( i )); target[i]->setPileRole(PatPile::Foundation); target[i]->setLayoutPos(targetOffsetDist + topRowDist * i, 0); target[i]->setSpread(0, 0); target[i]->setKeyboardSelectHint( KCardPile::NeverFocus ); target[i]->setKeyboardDropHint( KCardPile::ForceFocusTop ); } setActions(DealerScene::Demo | DealerScene::Hint); setSolver( new FreecellSolver( this ) ); setNeededFutureMoves( 4 ); // reserve some } void Freecell::restart( const QList & cards ) { QList cardList = cards; int column = 0; while ( !cardList.isEmpty() ) { addCardForDeal( store[column], cardList.takeLast(), true, store[0]->pos() ); column = (column + 1) % 8; } startDealAnimation(); } QString Freecell::solverFormat() const { QString output; QString tmp; for (int i = 0; i < 4 ; i++) { if (target[i]->isEmpty()) continue; tmp += suitToString(target[i]->topCard()->suit()) + '-' + rankToString(target[i]->topCard()->rank()) + ' '; } if (!tmp.isEmpty()) output += QStringLiteral("Foundations: %1\n").arg(tmp); tmp.truncate(0); for (int i = 0; i < 4 ; i++) { const auto fc = freecell[i]; tmp += (fc->isEmpty() ? QLatin1String("-") : cardToRankSuitString(fc->topCard())) + ' '; } if (!tmp.isEmpty()) { QString a = QStringLiteral("Freecells: %1\n"); output += a.arg(tmp); } for (int i = 0; i < 8 ; i++) - { - QList cards = store[i]->cards(); - for (QList::ConstIterator it = cards.constBegin(); it != cards.constEnd(); ++it) - output += cardToRankSuitString(*it) + ' '; - output += '\n'; - } + cardsListToLine(output, store[i]->cards()); return output; } void Freecell::cardsDroppedOnPile( const QList & cards, KCardPile * pile ) { if ( cards.size() <= 1 ) { DealerScene::moveCardsToPile( cards, pile, DURATION_MOVE ); return; } QList freeCells; for ( int i = 0; i < 4; ++i ) if ( freecell[i]->isEmpty() ) freeCells << freecell[i]; QList freeStores; for ( int i = 0; i < 8; ++i ) if ( store[i]->isEmpty() && store[i] != pile ) freeStores << store[i]; multiStepMove( cards, pile, freeStores, freeCells, DURATION_MOVE ); } bool Freecell::tryAutomaticMove(KCard *c) { // target move if (DealerScene::tryAutomaticMove(c)) return true; if (c->isAnimated()) return false; if (allowedToRemove(c->pile(), c) && c == c->pile()->topCard()) { for (int i = 0; i < 4; i++) { if (allowedToAdd( freecell[i], {c} )) { moveCardToPile( c, freecell[i], DURATION_MOVE ); return true; } } } return false; } bool Freecell::canPutStore( const KCardPile * pile, const QList & cards ) const { int freeCells = 0; for ( int i = 0; i < 4; ++i ) if ( freecell[i]->isEmpty() ) ++freeCells; int freeStores = 0; for ( int i = 0; i < 8; ++i ) if ( store[i]->isEmpty() && store[i] != pile ) ++freeStores; return cards.size() <= (freeCells + 1) << freeStores && ( pile->isEmpty() || ( pile->topCard()->rank() == cards.first()->rank() + 1 && pile->topCard()->color() != cards.first()->color() ) ); } bool Freecell::checkAdd(const PatPile * pile, const QList & oldCards, const QList & newCards) const { switch (pile->pileRole()) { case PatPile::Tableau: return canPutStore(pile, newCards); case PatPile::Cell: return oldCards.isEmpty() && newCards.size() == 1; case PatPile::Foundation: return checkAddSameSuitAscendingFromAce(oldCards, newCards); default: return false; } } bool Freecell::checkRemove(const PatPile * pile, const QList & cards) const { switch (pile->pileRole()) { case PatPile::Tableau: return isAlternateColorDescending(cards); case PatPile::Cell: return cards.first() == pile->topCard(); case PatPile::Foundation: default: return false; } } QList Freecell::getHints() { QList hintList = getSolverHints(); if ( isDemoActive() ) return hintList; foreach (PatPile * store, patPiles()) { if (store->isEmpty()) continue; QList cards = store->cards(); while (cards.count() && !cards.first()->isFaceUp()) cards.erase(cards.begin()); QList::Iterator iti = cards.begin(); while (iti != cards.end()) { if (allowedToRemove(store, (*iti))) { foreach (PatPile * dest, patPiles()) { int cardIndex = store->indexOf(*iti); if (cardIndex == 0 && dest->isEmpty() && !dest->isFoundation()) continue; if (!checkAdd(dest, dest->cards(), cards)) continue; if ( dest->isFoundation() ) // taken care by solver continue; QList cardsBelow = cards.mid(0, cardIndex); // if it could be here as well, then it's no use if ((cardsBelow.isEmpty() && !dest->isEmpty()) || !checkAdd(store, cardsBelow, cards)) { hintList << MoveHint( *iti, dest, 0 ); } else if (checkPrefering( dest, dest->cards(), cards ) && !checkPrefering( store, cardsBelow, cards )) { // if checkPrefers says so, we add it nonetheless hintList << MoveHint( *iti, dest, 0 ); } } } cards.erase(iti); iti = cards.begin(); } } return hintList; } static class FreecellDealerInfo : public DealerInfo { public: FreecellDealerInfo() : DealerInfo(I18N_NOOP("Freecell"), FreecellId) {} DealerScene *createGame() const Q_DECL_OVERRIDE { return new Freecell( this ); } } freecellDealerInfo; diff --git a/golf.cpp b/golf.cpp index 3eb7e96..2d4dd40 100644 --- a/golf.cpp +++ b/golf.cpp @@ -1,215 +1,202 @@ /* * Copyright (C) 2001-2009 Stephan Kulow * Copyright (C) 2010 Parker Coates * * License of original code: * ------------------------------------------------------------------------- * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * ------------------------------------------------------------------------- * * License of modifications/additions made after 2009-01-01: * ------------------------------------------------------------------------- * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ------------------------------------------------------------------------- */ #include "golf.h" #include "dealerinfo.h" #include "speeds.h" #include "patsolve/golfsolver.h" #include "pileutils.h" #include Golf::Golf( const DealerInfo * di ) : DealerScene( di ) { } void Golf::initialize() { const qreal dist_x = 1.11; const qreal smallNeg = -1e-6; setDeckContents(); talon = new PatPile( this, 0, QStringLiteral("talon") ); talon->setPileRole(PatPile::Stock); talon->setLayoutPos(0, smallNeg); talon->setSpread(0, 0); talon->setKeyboardSelectHint( KCardPile::NeverFocus ); talon->setKeyboardDropHint( KCardPile::NeverFocus ); connect( talon, &KCardPile::clicked, this, &DealerScene::drawDealRowOrRedeal ); waste = new PatPile( this, 8, QStringLiteral("waste") ); waste->setPileRole(PatPile::Foundation); waste->setLayoutPos(1.1, smallNeg); waste->setSpread(0.12, 0); waste->setRightPadding( 5 * dist_x ); waste->setWidthPolicy( KCardPile::GrowRight ); waste->setKeyboardSelectHint( KCardPile::NeverFocus ); waste->setKeyboardDropHint( KCardPile::AutoFocusTop ); for( int r = 0; r < 7; ++r ) { stack[r] = new PatPile( this, 1 + r, QStringLiteral("stack%1").arg(r) ); stack[r]->setPileRole(PatPile::Tableau); stack[r]->setLayoutPos(r*dist_x,0); // Manual tweak of the pile z values to make some animations better. stack[r]->setZValue((7-r)/100.0); stack[r]->setBottomPadding( 1.3 ); stack[r]->setHeightPolicy( KCardPile::GrowDown ); stack[r]->setKeyboardSelectHint( KCardPile::AutoFocusTop ); stack[r]->setKeyboardDropHint( KCardPile::NeverFocus ); } setActions(DealerScene::Hint | DealerScene::Demo | DealerScene::Draw); setSolver( new GolfSolver( this ) ); connect( this, &KCardScene::cardClicked, this, &DealerScene::tryAutomaticMove ); } bool Golf::checkAdd(const PatPile * pile, const QList & oldCards, const QList & newCards) const { return pile->pileRole() == PatPile::Foundation && ( newCards.first()->rank() == oldCards.last()->rank() + 1 || newCards.first()->rank() == oldCards.last()->rank() - 1 ); } bool Golf::checkRemove(const PatPile * pile, const QList & cards) const { return pile->pileRole() == PatPile::Tableau && cards.first() == pile->topCard(); } void Golf::restart( const QList & cards ) { QList cardList = cards; for ( int i = 0; i < 5; ++i ) for ( int r = 0; r < 7; ++r ) addCardForDeal( stack[r], cardList.takeLast(), true, stack[6]->pos() ); while ( !cardList.isEmpty() ) { KCard * c = cardList.takeFirst(); c->setPos( talon->pos() ); c->setFaceUp( false ); talon->add( c ); } startDealAnimation(); flipCardToPile(talon->topCard(), waste, DURATION_MOVE); emit newCardsPossible( true ); } bool Golf::newCards() { if ( talon->isEmpty() ) return false; flipCardToPile(talon->topCard(), waste, DURATION_MOVE); if ( talon->isEmpty() ) emit newCardsPossible( false ); return true; } bool Golf::drop() { for ( int i = 0; i < 7; ++i ) if ( !stack[i]->isEmpty() ) return false; if ( !talon->isEmpty() ) { flipCardToPile( talon->topCard(), waste, DURATION_MOVE ); takeState(); return true; } return false; } void Golf::setGameState( const QString & state ) { Q_UNUSED( state ); emit newCardsPossible( !talon->isEmpty() ); } QString Golf::solverFormat() const { QString output; output += QStringLiteral("Foundations: ") + (waste->isEmpty() ? QStringLiteral("-") : cardToRankSuitString(waste->topCard())) + '\n'; output += "Talon:"; for ( int i = talon->count()-1; i >= 0; --i ) { output += QStringLiteral(" ")+cardToRankSuitString(talon->at( i )); } output += "\n"; for (int i = 0; i < 7 ; i++) - { - QList cards = stack[i]->cards(); - bool first = true; - for (QList::ConstIterator it = cards.constBegin(); it != cards.constEnd(); ++it) - { - if (!first) - { - output += ' '; - } - first = false; - output += cardToRankSuitString(*it); - } - output += '\n'; - } + cardsListToLine(output, stack[i]->cards()); return output; } static class GolfDealerInfo : public DealerInfo { public: GolfDealerInfo() : DealerInfo(I18N_NOOP("Golf"), GolfId) {} DealerScene *createGame() const Q_DECL_OVERRIDE { return new Golf( this ); } } golfDealerInfo; diff --git a/pileutils.cpp b/pileutils.cpp index deab95d..af6cc73 100644 --- a/pileutils.cpp +++ b/pileutils.cpp @@ -1,188 +1,203 @@ /* * Copyright (C) 2010 Parker Coates * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "pileutils.h" #include "KCard" #include "KCardDeck" namespace { inline int alternateColor( int color ) { return color == KCardDeck::Red ? KCardDeck::Black : KCardDeck::Red; } } bool isSameSuitAscending( const QList & cards ) { if ( cards.size() <= 1 ) return true; int suit = cards.first()->suit(); int lastRank = cards.first()->rank(); for( int i = 1; i < cards.size(); ++i ) { ++lastRank; if ( cards[i]->suit() != suit || cards[i]->rank() != lastRank ) return false; } return true; } int countSameSuitDescendingSequences( const QList & cards ) { if ( cards.size() <= 1 ) return 0; int suit = cards.first()->suit(); int lastRank = cards.first()->rank(); int count = 1; for( int i = 1; i < cards.size(); ++i ) { --lastRank; if ( cards[i]->rank() != lastRank ) return -1; if ( cards[i]->suit() != suit ) { count++; suit = cards[i]->suit(); } } return count; } bool isSameSuitDescending( const QList & cards ) { if ( cards.size() <= 1 ) return true; int suit = cards.first()->suit(); int lastRank = cards.first()->rank(); for( int i = 1; i < cards.size(); ++i ) { --lastRank; if ( cards[i]->suit() != suit || cards[i]->rank() != lastRank ) return false; } return true; } bool isAlternateColorDescending( const QList & cards ) { if ( cards.size() <= 1 ) return true; int lastColor = cards.first()->color(); int lastRank = cards.first()->rank(); for( int i = 1; i < cards.size(); ++i ) { lastColor = alternateColor( lastColor ); --lastRank; if ( cards[i]->color() != lastColor || cards[i]->rank() != lastRank ) return false; } return true; } bool checkAddSameSuitAscendingFromAce( const QList & oldCards, const QList & newCards ) { if ( !isSameSuitAscending( newCards ) ) return false; if ( oldCards.isEmpty() ) return newCards.first()->rank() == KCardDeck::Ace; else return newCards.first()->suit() == oldCards.last()->suit() && newCards.first()->rank() == oldCards.last()->rank() + 1; } bool checkAddAlternateColorDescending( const QList & oldCards, const QList & newCards ) { return isAlternateColorDescending( newCards ) && ( oldCards.isEmpty() || ( newCards.first()->color() == alternateColor( oldCards.last()->color() ) && newCards.first()->rank() == oldCards.last()->rank() - 1 ) ); } bool checkAddAlternateColorDescendingFromKing( const QList & oldCards, const QList & newCards ) { if ( !isAlternateColorDescending( newCards ) ) return false; if ( oldCards.isEmpty() ) return newCards.first()->rank() == KCardDeck::King; else return newCards.first()->color() == alternateColor( oldCards.last()->color() ) && newCards.first()->rank() == oldCards.last()->rank() - 1; } QString suitToString(int s) { switch (s) { case KCardDeck::Clubs: return QStringLiteral("C"); case KCardDeck::Hearts: return QStringLiteral("H"); case KCardDeck::Diamonds: return QStringLiteral("D"); case KCardDeck::Spades: return QStringLiteral("S"); default: exit(-1); } return QString(); } QString rankToString(int r) { switch (r) { case KCardDeck::King: return QStringLiteral("K"); case KCardDeck::Ace: return QStringLiteral("A"); case KCardDeck::Jack: return QStringLiteral("J"); case KCardDeck::Queen: return QStringLiteral("Q"); case KCardDeck::Ten: return QStringLiteral("T"); default: return QString::number(r); } } QString cardToRankSuitString(const KCard *const card) { return rankToString(card->rank()) + suitToString(card->suit()); } + +void cardsListToLine(QString & output, const QList cards) +{ + bool first = true; + for (QList::ConstIterator it = cards.constBegin(); it != cards.constEnd(); ++it) + { + if (!first) + { + output += ' '; + } + first = false; + output += cardToRankSuitString(*it); + } + output += '\n'; +} diff --git a/pileutils.h b/pileutils.h index 77eccb0..05c8cd5 100644 --- a/pileutils.h +++ b/pileutils.h @@ -1,39 +1,40 @@ /* * Copyright (C) 2010 Parker Coates * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef PILEUTILS_H #define PILEUTILS_H class KCard; #include bool isSameSuitAscending( const QList & cards ); bool isSameSuitDescending( const QList & cards ); bool isAlternateColorDescending( const QList & cards ); int countSameSuitDescendingSequences( const QList & cards ); bool checkAddSameSuitAscendingFromAce( const QList & oldCards, const QList & newCards ); bool checkAddAlternateColorDescending( const QList & oldCards, const QList & newCards ); bool checkAddAlternateColorDescendingFromKing( const QList & oldCards, const QList & newCards ); extern QString suitToString(int s); extern QString rankToString(int r); extern QString cardToRankSuitString(const KCard*); +extern void cardsListToLine(QString & output, const QList cards); #endif diff --git a/simon.cpp b/simon.cpp index 90ef41e..f540570 100644 --- a/simon.cpp +++ b/simon.cpp @@ -1,192 +1,189 @@ /* * Copyright (C) 2000-2009 Stephan Kulow * Copyright (C) 2010 Parker Coates * * License of original code: * ------------------------------------------------------------------------- * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * ------------------------------------------------------------------------- * * License of modifications/additions made after 2009-01-01: * ------------------------------------------------------------------------- * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ------------------------------------------------------------------------- */ #include "simon.h" #include "dealerinfo.h" #include "pileutils.h" #include "patsolve/simonsolver.h" #include Simon::Simon( const DealerInfo * di ) : DealerScene( di ) { } void Simon::initialize() { setDeckContents(); const qreal dist_x = 1.11; for ( int i = 0; i < 4; ++i ) { target[i] = new PatPile( this, i + 1, QStringLiteral( "target%1" ).arg( i ) ); target[i]->setPileRole(PatPile::Foundation); target[i]->setLayoutPos((i+3)*dist_x, 0); target[i]->setSpread(0, 0); target[i]->setKeyboardSelectHint( KCardPile::NeverFocus ); target[i]->setKeyboardDropHint( KCardPile::AutoFocusTop ); } for ( int i = 0; i < 10; ++i ) { store[i] = new PatPile( this, 5 + i, QStringLiteral( "store%1" ).arg( i ) ); store[i]->setPileRole(PatPile::Tableau); store[i]->setLayoutPos(dist_x*i, 1.2); store[i]->setBottomPadding( 2.5 ); store[i]->setHeightPolicy( KCardPile::GrowDown ); store[i]->setZValue( 0.01 * i ); store[i]->setKeyboardSelectHint( KCardPile::AutoFocusDeepestRemovable ); store[i]->setKeyboardDropHint( KCardPile::AutoFocusTop ); } setActions(DealerScene::Hint | DealerScene::Demo); setSolver( new SimonSolver( this ) ); //setNeededFutureMoves( 1 ); // could be some nonsense moves } void Simon::restart( const QList & cards ) { QList cardList = cards; QPointF initPos( 0, -deck()->cardHeight() ); for ( int piles = 9; piles >= 3; --piles ) for ( int j = 0; j < piles; ++j ) addCardForDeal( store[j], cardList.takeLast(), true, initPos ); for ( int j = 0; j < 10; ++j ) addCardForDeal( store[j], cardList.takeLast(), true, initPos ); Q_ASSERT( cardList.isEmpty() ); startDealAnimation(); } bool Simon::checkPrefering(const PatPile * pile, const QList & oldCards, const QList & newCards) const { return pile->pileRole() == PatPile::Tableau && !oldCards.isEmpty() && oldCards.last()->suit() == newCards.first()->suit(); } bool Simon::checkAdd(const PatPile * pile, const QList & oldCards, const QList & newCards) const { if (pile->pileRole() == PatPile::Tableau) { if (! (oldCards.isEmpty() || oldCards.last()->rank() == newCards.first()->rank() + 1 )) { return false; } int seqs_count = countSameSuitDescendingSequences(newCards); if (seqs_count < 0) return false; // This is similar to the supermoves of Freecell - we can use empty // columns to temporarily hold intermediate sub-sequences which are // not the same suit - only a "false" parent. // Shlomi Fish int empty_piles_count = 0; for (int i = 0; i < 10; ++i ) if (store[i]->isEmpty() && ( store[i]->index() != pile->index() )) empty_piles_count++; return (seqs_count <= (1 << empty_piles_count)); } else { return oldCards.isEmpty() && newCards.first()->rank() == KCardDeck::King && newCards.last()->rank() == KCardDeck::Ace && isSameSuitDescending(newCards); } } bool Simon::checkRemove(const PatPile * pile, const QList & cards) const { if (pile->pileRole() != PatPile::Tableau) return false; int seqs_count = countSameSuitDescendingSequences(cards); return (seqs_count >= 0); } QString Simon::solverFormat() const { QString output; QString tmp; for (int i = 0; i < 4 ; i++) { if (target[i]->isEmpty()) continue; tmp += suitToString(target[i]->topCard()->suit()) + "-K "; } if (!tmp.isEmpty()) output += QStringLiteral("Foundations: %1\n").arg(tmp); for (int i = 0; i < 10 ; i++) { - QList cards = store[i]->cards(); - for (QList::ConstIterator it = cards.constBegin(); it != cards.constEnd(); ++it) - output += cardToRankSuitString(*it) + ' '; - output += '\n'; + cardsListToLine(output, store[i]->cards()); } return output; } static class SimonDealerInfo : public DealerInfo { public: SimonDealerInfo() : DealerInfo(I18N_NOOP("Simple Simon"), SimpleSimonId) {} DealerScene *createGame() const Q_DECL_OVERRIDE { return new Simon( this ); } } simonDealerInfo;