solitaire_04.py Full Listing#
solitaire_04.py#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | """ Solitaire clone. """ import arcade # Screen title and size SCREEN_WIDTH = 1024 SCREEN_HEIGHT = 768 SCREEN_TITLE = "Drag and Drop Cards" # Constants for sizing CARD_SCALE = 0.6 # How big are the cards? CARD_WIDTH = 140 * CARD_SCALE CARD_HEIGHT = 190 * CARD_SCALE # How big is the mat we'll place the card on? MAT_PERCENT_OVERSIZE = 1.25 MAT_HEIGHT = int(CARD_HEIGHT * MAT_PERCENT_OVERSIZE) MAT_WIDTH = int(CARD_WIDTH * MAT_PERCENT_OVERSIZE) # How much space do we leave as a gap between the mats? # Done as a percent of the mat size. VERTICAL_MARGIN_PERCENT = 0.10 HORIZONTAL_MARGIN_PERCENT = 0.10 # The Y of the bottom row (2 piles) BOTTOM_Y = MAT_HEIGHT / 2 + MAT_HEIGHT * VERTICAL_MARGIN_PERCENT # The X of where to start putting things on the left side START_X = MAT_WIDTH / 2 + MAT_WIDTH * HORIZONTAL_MARGIN_PERCENT # The Y of the top row (4 piles) TOP_Y = SCREEN_HEIGHT - MAT_HEIGHT / 2 - MAT_HEIGHT * VERTICAL_MARGIN_PERCENT # The Y of the middle row (7 piles) MIDDLE_Y = TOP_Y - MAT_HEIGHT - MAT_HEIGHT * VERTICAL_MARGIN_PERCENT # How far apart each pile goes X_SPACING = MAT_WIDTH + MAT_WIDTH * HORIZONTAL_MARGIN_PERCENT # Card constants CARD_VALUES = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] CARD_SUITS = ["Clubs", "Hearts", "Spades", "Diamonds"] class Card(arcade.Sprite): """ Card sprite """ def __init__(self, suit, value, scale=1): """ Card constructor """ # Attributes for suit and value self.suit = suit self.value = value # Image to use for the sprite when face up self.image_file_name = f":resources:images/cards/card{self.suit}{self.value}.png" # Call the parent super().__init__(self.image_file_name, scale, hit_box_algorithm="None") class MyGame(arcade.Window): """ 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 arcade.set_background_color(arcade.color.AMAZON) # List of cards we are dragging with the mouse self.held_cards = None # Original location of cards we are dragging with the mouse in case # they have to go back. self.held_cards_original_position = None # Sprite list with all the mats tha cards lay on. self.pile_mat_list = None def setup(self): """ Set up the game here. Call this function to restart the game. """ # List of cards we are dragging with the mouse self.held_cards = [] # Original location of cards we are dragging with the mouse in case # they have to go back. self.held_cards_original_position = [] # --- Create the mats the cards go on. # Sprite list with all the mats tha cards lay on. self.pile_mat_list: arcade.SpriteList = arcade.SpriteList() # Create the mats for the bottom face down and face up piles pile = arcade.SpriteSolidColor(MAT_WIDTH, MAT_HEIGHT, arcade.csscolor.DARK_OLIVE_GREEN) pile.position = START_X, BOTTOM_Y self.pile_mat_list.append(pile) pile = arcade.SpriteSolidColor(MAT_WIDTH, MAT_HEIGHT, arcade.csscolor.DARK_OLIVE_GREEN) pile.position = START_X + X_SPACING, BOTTOM_Y self.pile_mat_list.append(pile) # Create the seven middle piles for i in range(7): pile = arcade.SpriteSolidColor(MAT_WIDTH, MAT_HEIGHT, arcade.csscolor.DARK_OLIVE_GREEN) pile.position = START_X + i * X_SPACING, MIDDLE_Y self.pile_mat_list.append(pile) # Create the top "play" piles for i in range(4): pile = arcade.SpriteSolidColor(MAT_WIDTH, MAT_HEIGHT, arcade.csscolor.DARK_OLIVE_GREEN) pile.position = START_X + i * X_SPACING, TOP_Y self.pile_mat_list.append(pile) # Sprite list with all the cards, no matter what pile they are in. self.card_list = arcade.SpriteList() # Create every card for card_suit in CARD_SUITS: for card_value in CARD_VALUES: card = Card(card_suit, card_value, CARD_SCALE) card.position = START_X, BOTTOM_Y self.card_list.append(card) def on_draw(self): """ Render the screen. """ # Clear the screen self.clear() # Draw the mats the cards go on to self.pile_mat_list.draw() # Draw the cards self.card_list.draw() def pull_to_top(self, card): """ Pull card to top of rendering order (last to render, looks on-top) """ # Find the index of the card index = self.card_list.index(card) # Loop and pull all the other cards down towards the zero end for i in range(index, len(self.card_list) - 1): self.card_list[i] = self.card_list[i + 1] # Put this card at the right-side/top/size of list self.card_list[len(self.card_list) - 1] = card def on_mouse_press(self, x, y, button, key_modifiers): """ 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] # All other cases, grab the face-up card we are clicking on self.held_cards = [primary_card] # Save the position self.held_cards_original_position = [self.held_cards[0].position] # Put on top in drawing order self.pull_to_top(self.held_cards[0]) 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: return # We are no longer holding cards self.held_cards = [] def on_mouse_motion(self, x: float, y: float, dx: float, dy: float): """ User moves mouse """ # If we are holding cards, move them with the mouse for card in self.held_cards: card.center_x += dx card.center_y += dy def main(): """ Main function """ window = MyGame() window.setup() arcade.run() if __name__ == "__main__": main() |