summaryrefslogtreecommitdiffstats
path: root/kpat/grandf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kpat/grandf.cpp')
-rw-r--r--kpat/grandf.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/kpat/grandf.cpp b/kpat/grandf.cpp
new file mode 100644
index 00000000..9756b840
--- /dev/null
+++ b/kpat/grandf.cpp
@@ -0,0 +1,227 @@
+/***********************-*-C++-*-********
+
+ grandf.cpp implements a patience card game
+
+ Copyright (C) 1995 Paul Olav Tvete
+ (C) 2000 Stephan Kulow
+ * 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.
+
+****************************************/
+
+#include "grandf.h"
+#include <klocale.h>
+#include "deck.h"
+#include <kaction.h>
+#include <assert.h>
+#include "cardmaps.h"
+
+Grandf::Grandf( KMainWindow* parent, const char *name )
+ : Dealer( parent, name )
+{
+ deck = Deck::new_deck(this);
+ deck->hide();
+
+ const int distx = cardMap::CARDX() * 14 / 10;
+
+ for (int i=0; i<4; i++) {
+ target[i] = new Pile(i+1, this);
+ target[i]->move(10+(i+1)*distx, 10);
+ target[i]->setType(Pile::KlondikeTarget);
+ }
+
+ for (int i=0; i<7; i++) {
+ store[i] = new Pile(5+i, this);
+ store[i]->move(10+distx*i, 10 + cardMap::CARDY() * 15 / 10);
+ store[i]->setAddFlags(Pile::addSpread | Pile::several);
+ store[i]->setRemoveFlags(Pile::several | Pile::autoTurnTop);
+ store[i]->setCheckIndex(1);
+ }
+
+ setActions(Dealer::Hint | Dealer::Demo | Dealer::Redeal);
+}
+
+void Grandf::restart() {
+ deck->collectAndShuffle();
+ deal();
+ numberOfDeals = 1;
+}
+
+void Grandf::redeal() {
+ unmarkAll();
+
+ if (numberOfDeals < 3) {
+ collect();
+ deal();
+ numberOfDeals++;
+ }
+ if (numberOfDeals == 3) {
+ aredeal->setEnabled(false);
+ }
+ takeState();
+}
+
+Card *Grandf::demoNewCards()
+{
+ if (numberOfDeals < 3) {
+ redeal();
+ return store[3]->top();
+ } else
+ return 0;
+}
+
+void Grandf::deal() {
+ int start = 0;
+ int stop = 7-1;
+ int dir = 1;
+
+ for (int round=0; round < 7; round++)
+ {
+ int i = start;
+ do
+ {
+ Card *next = deck->nextCard();
+ if (next)
+ store[i]->add(next, i != start, true);
+ i += dir;
+ } while ( i != stop + dir);
+ int t = start;
+ start = stop;
+ stop = t+dir;
+ dir = -dir;
+ }
+
+ int i = 0;
+ Card *next = deck->nextCard();
+ while (next)
+ {
+ store[i+1]->add(next, false , true);
+ next = deck->nextCard();
+ i = (i+1)%6;
+ }
+
+ for (int round=0; round < 7; round++)
+ {
+ Card *c = store[round]->top();
+ if (c)
+ c->turn(true);
+ }
+ aredeal->setEnabled(true);
+ canvas()->update();
+}
+
+/*****************************
+
+ Does the collecting step of the game
+
+ NOTE: this is not quite correct -- the piles should be turned
+ facedown (ie partially reversed) during collection.
+
+******************************/
+void Grandf::collect() {
+ unmarkAll();
+
+ for (int pos = 6; pos >= 0; pos--) {
+ CardList p = store[pos]->cards();
+ for (CardList::ConstIterator it = p.begin(); it != p.end(); ++it)
+ deck->add(*it, true, false);
+ }
+}
+
+bool Grandf::checkAdd( int checkIndex, const Pile *c1, const CardList& c2) const {
+ assert (checkIndex == 1);
+ if (c1->isEmpty())
+ return c2.first()->rank() == Card::King;
+ else
+ return (c2.first()->rank() == c1->top()->rank() - 1)
+ && c2.first()->suit() == c1->top()->suit();
+}
+
+QString Grandf::getGameState() const
+{
+ return QString::number(numberOfDeals);
+}
+
+void Grandf::setGameState( const QString &s)
+{
+ numberOfDeals = s.toInt();
+ aredeal->setEnabled(numberOfDeals < 3);
+}
+
+bool Grandf::isGameLost() const
+{
+ // If we can redeal, then nothing's lost yet.
+ if (numberOfDeals <3)
+ return false;
+
+ // Work through the stores, look for killer criteria.
+ for(int i=0; i < 7; i++) {
+
+ /* If this store is empty, then iterate through the other stores and
+ * check if there is a (visible) King card. If so, then we could move
+ * that to the free store (which means a turn is possible, so the
+ * game is not lost yet).
+ */
+ if(store[i]->isEmpty()){
+ for(int i2=1; i2 < 7; i2++) {
+ int j=(i+i2) % 7;
+ CardList p = store[j]->cards();
+ for (CardList::ConstIterator it = p.begin(); it != p.end(); ++it){
+ Card *c= *it;
+ if( it != p.begin() && c->realFace() && c->rank() == Card::King)
+ return false;
+ }
+ }
+ }
+ else{
+ /* If this store has an Ace as it's top card, then we can start a
+ * new target pile!
+ */
+ if(store[i]->top()->rank() == Card::Ace)
+ return false;
+
+ /* Check whether the top card of this store could be added to
+ * any of the target piles.
+ */
+ for(int j=0; j <4; j++)
+ if( !target[j]->isEmpty())
+ if(store[i]->top()->suit() == target[j]->top()->suit())
+ if( store[i]->top()->rank() == target[j]->top()->rank() +1)
+ return false;
+
+ /* Check whether any (group of) cards from another store could
+ * be put onto this store's top card.
+ */
+ for(int i2=1; i2 < 7; i2++) {
+ int j=(i+i2) % 7;
+ CardList p = store[j]->cards();
+ for (CardList::ConstIterator it = p.begin(); it != p.end(); ++it){
+ Card *c= *it;
+ if( c->realFace() &&
+ c->rank() == (store[i]->top()->rank()-1) &&
+ c->suit() == store[i]->top()->suit() )
+ return false;
+ }
+ }
+ }
+ }
+ return true; // can't move.
+}
+
+static class LocalDealerInfo1 : public DealerInfo
+{
+public:
+ LocalDealerInfo1() : DealerInfo(I18N_NOOP("&Grandfather"), 1) {}
+ virtual Dealer *createGame(KMainWindow *parent) { return new Grandf(parent); }
+} gfdi;
+
+#include "grandf.moc"