solitaire_07.py Diff#

solitaire_07.py#
--- /home/docs/checkouts/readthedocs.org/user_builds/arcade-library/checkouts/latest/doc/tutorials/card_game/solitaire_06.py
+++ /home/docs/checkouts/readthedocs.org/user_builds/arcade-library/checkouts/latest/doc/tutorials/card_game/solitaire_07.py
@@ -45,6 +45,25 @@
 CARD_VALUES = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
 CARD_SUITS = ["Clubs", "Hearts", "Spades", "Diamonds"]
 
+# If we fan out cards stacked on each other, how far apart to fan them?
+CARD_VERTICAL_OFFSET = CARD_HEIGHT * CARD_SCALE * 0.3
+
+# Constants that represent "what pile is what" for the game
+PILE_COUNT = 13
+BOTTOM_FACE_DOWN_PILE = 0
+BOTTOM_FACE_UP_PILE = 1
+PLAY_PILE_1 = 2
+PLAY_PILE_2 = 3
+PLAY_PILE_3 = 4
+PLAY_PILE_4 = 5
+PLAY_PILE_5 = 6
+PLAY_PILE_6 = 7
+PLAY_PILE_7 = 8
+TOP_PILE_1 = 9
+TOP_PILE_2 = 10
+TOP_PILE_3 = 11
+TOP_PILE_4 = 12
+
 
 class Card(arcade.Sprite):
     """ Card sprite """
@@ -83,6 +102,9 @@
 
         # Sprite list with all the mats tha cards lay on.
         self.pile_mat_list = None
+
+        # Create a list of lists, each holds a pile of cards.
+        self.piles = None
 
     def setup(self):
         """ Set up the game here. Call this function to restart the game. """
@@ -137,6 +159,13 @@
             pos2 = random.randrange(len(self.card_list))
             self.card_list.swap(pos1, pos2)
 
+        # Create a list of lists, each holds a pile of cards.
+        self.piles = [[] for _ in range(PILE_COUNT)]
+
+        # Put all the cards in the bottom face-down pile
+        for card in self.card_list:
+            self.piles[BOTTOM_FACE_DOWN_PILE].append(card)
+
     def on_draw(self):
         """ Render the screen. """
         # Clear the screen
@@ -174,6 +203,24 @@
             # Put on top in drawing order
             self.pull_to_top(self.held_cards[0])
 
+    def remove_card_from_pile(self, card):
+        """ Remove card from whatever pile it was in. """
+        for pile in self.piles:
+            if card in pile:
+                pile.remove(card)
+                break
+
+    def get_pile_for_card(self, card):
+        """ What pile is this card in? """
+        for index, pile in enumerate(self.piles):
+            if card in pile:
+                return index
+
+    def move_card_to_new_pile(self, card, pile_index):
+        """ Move the card to a new pile """
+        self.remove_card_from_pile(card)
+        self.piles[pile_index].append(card)
+
     def on_mouse_release(self, x: float, y: float, button: int,
                          modifiers: int):
         """ Called when the user presses a mouse button. """
@@ -189,13 +236,46 @@
         # See if we are in contact with the closest pile
         if arcade.check_for_collision(self.held_cards[0], pile):
 
-            # For each held card, move it to the pile we dropped on
-            for i, dropped_card in enumerate(self.held_cards):
-                # Move cards to proper position
-                dropped_card.position = pile.center_x, pile.center_y
-
-            # Success, don't reset position of cards
-            reset_position = False
+            # What pile is it?
+            pile_index = self.pile_mat_list.index(pile)
+
+            #  Is it the same pile we came from?
+            if pile_index == self.get_pile_for_card(self.held_cards[0]):
+                # If so, who cares. We'll just reset our position.
+                pass
+
+            # Is it on a middle play pile?
+            elif PLAY_PILE_1 <= pile_index <= PLAY_PILE_7:
+                # Are there already cards there?
+                if len(self.piles[pile_index]) > 0:
+                    # Move cards to proper position
+                    top_card = self.piles[pile_index][-1]
+                    for i, dropped_card in enumerate(self.held_cards):
+                        dropped_card.position = top_card.center_x, \
+                                                top_card.center_y - CARD_VERTICAL_OFFSET * (i + 1)
+                else:
+                    # Are there no cards in the middle play pile?
+                    for i, dropped_card in enumerate(self.held_cards):
+                        # Move cards to proper position
+                        dropped_card.position = pile.center_x, \
+                                                pile.center_y - CARD_VERTICAL_OFFSET * i
+
+                for card in self.held_cards:
+                    # Cards are in the right position, but we need to move them to the right list
+                    self.move_card_to_new_pile(card, pile_index)
+
+                # Success, don't reset position of cards
+                reset_position = False
+
+            # Release on top play pile? And only one card held?
+            elif TOP_PILE_1 <= pile_index <= TOP_PILE_4 and len(self.held_cards) == 1:
+                # Move position of card to pile
+                self.held_cards[0].position = pile.position
+                # Move card to card list
+                for card in self.held_cards:
+                    self.move_card_to_new_pile(card, pile_index)
+
+                reset_position = False
 
         if reset_position:
             # Where-ever we were dropped, it wasn't valid. Reset the each card's position