[Kde-games-devel] Updated patch for bug 16214 (Klondike: Clean up cards that are no longer needed.)
Erik Sigra
kde-games-devel@mail.kde.org
Sun, 2 Feb 2003 21:47:39 +0100
--Boundary-00=_rPYP+H2Id6LKWQA
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
I have updated the patch for bug 16214 (Klondike: Clean up cards that are no
longer needed.). It is now carefully commented. Please review and test:
http://bugs.kde.org/show_bug.cgi?id=16214
--Boundary-00=_rPYP+H2Id6LKWQA
Content-Type: text/x-diff;
charset="us-ascii";
name="bug16214.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="bug16214.diff"
--- klondike.h.orig 2003-02-02 18:36:37.000000000 +0100
+++ klondike.h 2003-02-02 18:37:52.000000000 +0100
@@ -63,5 +63,6 @@
KlondikePile *pile;
Deck* deck;
- Card::Values lowest_card[2];
+ Card::Values target_tops[4];
+ bool noLongerNeeded(const Card &);
};
--- klondike.cpp.orig 2003-02-02 18:36:45.000000000 +0100
+++ klondike.cpp 2003-02-02 21:12:25.000000000 +0100
@@ -95,4 +95,63 @@
}
+// This function returns true when it is certain that the card t is no longer
+// needed on any of the play piles. This function is recursive but the
+// recursion will not get deep.
+//
+// To determine wether a card is no longer needed on any of the play piles we
+// obviously must know what a card can be used for there. According to the
+// rules a card can be used to store another card with 1 less unit of value
+// and opposite color. This is the only thing that a card can be used for
+// there. Therefore the cards with lowest value (1) are useless there (base
+// case). The other cards each have 2 cards that can be stored on them, let us
+// call those 2 cards *depending cards*.
+//
+// The object of the game is to put all cards on the target piles. Therefore
+// cards that are no longer needed on any of the play piles should be put on
+// the target piles if possible. Cards on the target piles can not be moved
+// and they can not store any of its depending cards. Let us call this that
+// the cards on the target piles are *out of play*.
+//
+// The simple and obvious rule is:
+// A card is no longer needed when both of its depending cards are out of
+// play.
+//
+// But using only the simplest rule to determine if a card is no longer
+// needed on any of the play piles is not ambitios enough. Therefore, if a
+// depending card is not out of play, we test if it could become out of play.
+// The requirement for getting a card out of play is that it can be placed on
+// a target pile and that it is no longer needed on any of the play piles
+// (this is why this function is recursive). This more ambitious rule lets
+// us extend the base case with the second lowest value (2).
+bool Klondike::noLongerNeeded(const Card & t) {
+
+ if (t.value() <= Card::Two) return true; // Base case.
+
+ // Find the 2 suits of opposite color. "- 1" is used here because the
+ // siuts are ranged 1 .. 4 but target_tops is indexed 0 .. 3. (Of course
+ // the subtraction of 1 does not affect performance because it is a
+ // constant expression that is calculated at compile time).
+ unsigned char a = Card::Clubs - 1, b = Card::Spades - 1;
+ if (t.suit() == Card::Clubs or t.suit() == Card::Spades)
+ a = Card::Diamonds - 1, b = Card::Hearts - 1;
+
+ const Card::Values depending_value
+ = static_cast<Card::Values>(t.value() - 1);
+ return
+ (((target_tops[a] >= depending_value)
+ or
+ ((target_tops[a] >= depending_value - 1)
+ and
+ (noLongerNeeded
+ (Card(depending_value, static_cast<Card::Suits>(a + 1))))))
+ and
+ ((target_tops[b] >= depending_value)
+ or
+ ((target_tops[b] >= depending_value - 1)
+ and
+ (noLongerNeeded
+ (Card(depending_value, static_cast<Card::Suits>(b + 1)))))));
+}
+
bool Klondike::tryToDrop(Card *t)
{
@@ -102,8 +161,9 @@
// kdDebug(11111) << "tryToDrop " << t->name() << endl;
- bool shoulddrop = (t->value() <= Card::Two || t->value() <= lowest_card[t->isRed() ? 1 : 0] + 1);
Pile *tgt = findTarget(t);
if (tgt) {
- newHint(new MoveHint(t, tgt, shoulddrop));
+ newHint
+ (new MoveHint
+ (t, tgt, noLongerNeeded(Card(t->value(), t->suit()))));
return true;
}
@@ -113,5 +173,6 @@
void Klondike::getHints() {
- int tops[4] = {0, 0, 0, 0};
+ target_tops[0] = target_tops[1] = target_tops[2] = target_tops[3]
+ = Card::None;
for( int i = 0; i < 4; i++ )
@@ -119,11 +180,7 @@
Card *c = target[i]->top();
if (!c) continue;
- tops[c->suit() - 1] = c->value();
+ target_tops[c->suit() - 1] = c->value();
}
- lowest_card[0] = static_cast<Card::Values>(QMIN(tops[1], tops[2])); // red
- lowest_card[1] = static_cast<Card::Values>(QMIN(tops[0], tops[3])); // black
-
-// kdDebug(11111) << "startAutoDrop red:" << lowest_card[0] << " black:" << lowest_card[1] << endl;
Card* t[7];
--Boundary-00=_rPYP+H2Id6LKWQA--