solitaire_11.py Diff
solitaire_11.py
--- /home/docs/checkouts/readthedocs.org/user_builds/arcade-library/checkouts/latest/doc/tutorials/card_game/solitaire_10.py
+++ /home/docs/checkouts/readthedocs.org/user_builds/arcade-library/checkouts/latest/doc/tutorials/card_game/solitaire_11.py
@@ -1,7 +1,9 @@
"""
Solitaire clone.
"""
+
import random
+
import arcade
# Screen title and size
@@ -69,10 +71,10 @@
class Card(arcade.Sprite):
- """ Card sprite """
+ """Card sprite"""
def __init__(self, suit, value, scale=1):
- """ Card constructor """
+ """Card constructor"""
# Attributes for suit and value
self.suit = suit
@@ -84,29 +86,29 @@
super().__init__(FACE_DOWN_IMAGE, scale, hit_box_algorithm="None")
def face_down(self):
- """ Turn card face-down """
+ """Turn card face-down"""
self.texture = arcade.load_texture(FACE_DOWN_IMAGE)
self.is_face_up = False
def face_up(self):
- """ Turn card face-up """
+ """Turn card face-up"""
self.texture = arcade.load_texture(self.image_file_name)
self.is_face_up = True
@property
def is_face_down(self):
- """ Is this card face down? """
+ """Is this card face down?"""
return not self.is_face_up
class MyGame(arcade.Window):
- """ Main application class. """
+ """Main application class."""
def __init__(self):
super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
# Sprite list with all the cards, no matter what pile they are in.
- self.card_list = None
+ self.card_list: arcade.SpriteList | None = None
self.background_color = arcade.color.AMAZON
@@ -124,7 +126,7 @@
self.piles = None
def setup(self):
- """ Set up the game here. Call this function to restart the game. """
+ """Set up the game here. Call this function to restart the game."""
# List of cards we are dragging with the mouse
self.held_cards = []
@@ -202,7 +204,7 @@
self.piles[i][-1].face_up()
def on_draw(self):
- """ Render the screen. """
+ """Render the screen."""
# Clear the screen
self.clear()
@@ -213,21 +215,26 @@
self.card_list.draw()
def pull_to_top(self, card: arcade.Sprite):
- """ Pull card to top of rendering order (last to render, looks on-top) """
+ """Pull card to top of rendering order (last to render, looks on-top)"""
# Remove, and append to the end
self.card_list.remove(card)
self.card_list.append(card)
+ def on_key_press(self, symbol: int, modifiers: int):
+ """User presses key"""
+ if symbol == arcade.key.R:
+ # Restart
+ self.setup()
+
def on_mouse_press(self, x, y, button, key_modifiers):
- """ Called when the user presses a mouse button. """
+ """Called when the user presses a mouse button."""
# Get list of cards we've clicked on
cards = arcade.get_sprites_at_point((x, y), self.card_list)
# Have we clicked on a card?
if len(cards) > 0:
-
# Might be a stack of cards, get the top one
primary_card = cards[-1]
assert isinstance(primary_card, Card)
@@ -235,7 +242,27 @@
# Figure out what pile the card is in
pile_index = self.get_pile_for_card(primary_card)
- if primary_card.is_face_down:
+ # Are we clicking on the bottom deck, to flip three cards?
+ if pile_index == BOTTOM_FACE_DOWN_PILE:
+ # Flip three cards
+ for i in range(3):
+ # If we ran out of cards, stop
+ if len(self.piles[BOTTOM_FACE_DOWN_PILE]) == 0:
+ break
+ # Get top card
+ card = self.piles[BOTTOM_FACE_DOWN_PILE][-1]
+ # Flip face up
+ card.face_up()
+ # Move card position to bottom-right face up pile
+ card.position = self.pile_mat_list[BOTTOM_FACE_UP_PILE].position
+ # Remove card from face down pile
+ self.piles[BOTTOM_FACE_DOWN_PILE].remove(card)
+ # Move card to face up list
+ self.piles[BOTTOM_FACE_UP_PILE].append(card)
+ # Put on top draw-order wise
+ self.pull_to_top(card)
+
+ elif primary_card.is_face_down:
# Is the card face down? In one of those middle 7 piles? Then flip up
primary_card.face_up()
else:
@@ -254,27 +281,47 @@
self.held_cards_original_position.append(card.position)
self.pull_to_top(card)
+ else:
+ # Click on a mat instead of a card?
+ mats = arcade.get_sprites_at_point((x, y), self.pile_mat_list)
+
+ if len(mats) > 0:
+ mat = mats[0]
+ mat_index = self.pile_mat_list.index(mat)
+
+ # Is it our turned over flip mat? and no cards on it?
+ if (
+ mat_index == BOTTOM_FACE_DOWN_PILE
+ and len(self.piles[BOTTOM_FACE_DOWN_PILE]) == 0
+ ):
+ # Flip the deck back over so we can restart
+ temp_list = self.piles[BOTTOM_FACE_UP_PILE].copy()
+ for card in reversed(temp_list):
+ card.face_down()
+ self.piles[BOTTOM_FACE_UP_PILE].remove(card)
+ self.piles[BOTTOM_FACE_DOWN_PILE].append(card)
+ card.position = self.pile_mat_list[BOTTOM_FACE_DOWN_PILE].position
+
def remove_card_from_pile(self, card):
- """ Remove card from whatever pile it was in. """
+ """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? """
+ """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 """
+ """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. """
+ def on_mouse_release(self, x: float, y: float, button: int, modifiers: int):
+ """Called when the user presses a mouse button."""
# If we don't have any cards, who cares
if len(self.held_cards) == 0:
@@ -286,7 +333,6 @@
# See if we are in contact with the closest pile
if arcade.check_for_collision(self.held_cards[0], pile):
-
# What pile is it?
pile_index = self.pile_mat_list.index(pile)
@@ -302,14 +348,18 @@
# 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)
+ 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
+ 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
@@ -338,7 +388,7 @@
self.held_cards = []
def on_mouse_motion(self, x: float, y: float, dx: float, dy: float):
- """ User moves mouse """
+ """User moves mouse"""
# If we are holding cards, move them with the mouse
for card in self.held_cards:
@@ -347,7 +397,7 @@
def main():
- """ Main function """
+ """Main function"""
window = MyGame()
window.setup()
arcade.run()