This is python3. Please help me out. Develop the following GUI interface to allo
ID: 3677573 • Letter: T
Question
This is python3. Please help me out.
Develop the following GUI interface to allow the user to specify the number of rows and number of columns of cards to be shown to the user. Show default values 2 and 2 for number of rows and number of columns. The buttons "New Game" and "Turn Over" span two column-cells each.
Fig 1. The GUI when the program first starts.
When the user clicks the "New Game" button, the program will read the number of rows and columns entered by the user. To keep the GUI's size manageable, the GUI will show at most 20 cards. Display an error in an error dialog box if number_of_row times number_of_columns is odd or greater than 20. Sample screen shots are as follows:
Fig 2. An error message in an error dialog box.
Fig 3. Another error message in an error dialog box.
If the entered values for number of rows and columns are valid. The program will create a deck object with the required pairs of cards. The cards must have ranks from 1 through (number of rows * number of columns) // 2. Each pair of cards must be of the same suit (Spades, Clubs, Diamonds, or Hearts). Select the suit for a pair of cards at random by using the Python code suit = random.choice(['s', 'c', 'd', 'h']). The program will then shuffle the deck of cards and create labels with card images as dealt from the deck. The cards must be gridded below the action buttons using the exact number of rows and columns as specified by the user. So, for example, if the user specifies 3 rows and 4 columns, the cards will be displayed in 3 rows and 4 columns. Sample screen shot is as follows:
Fig 4. The GUI from Fig. 1 after pressing the "New Game" button.
Fig 5. shows the GUI from Fig 4. after the user specifies 4 rows and 4 columns and presses the "New Game" button.
Fig 5. The GUI after changing number of rows to 4 and pressing the "New Game" button.
Clicking the "Turn Over" button will flip all the cards' images over, so if the images are face up they will be turned face down, and vice versa. Use the same back image for all cards. For example, Fig. 6 shows the GUI from Fig. 5 after the "Turn Over" button is clicked.
Fig 6. The GUI from Fig 5. after pressing the "Turn Over" button.
If the user then clicks the "Turn Over" button one more time, all the cards will be turned face up and the result will be as shown in Fig. 7, which is exactly the same as Fig. 5.
Fig 7. The GUI from Fig 6. after pressing the "Turn Over" button.
Extra Feature: [25 Extra Points]
Associate the left-mouse button press event, (<Button-1>), with the cards' labels so that the user can play the memory matching game. When a card is clicked, it will be flipped over, so that if it is face down it will be turned face up, and vice versa. The game will be played as follows. The user specifies the number of rows and columns and clicks the "New Game" button. Cards will be displayed in the GUI face up as shown in Fig. 4 and Fig. 5 above. The user will try to memorize all the cards' locations on the GUI. The user then clicks the "Turn Over" button to turn all the cards face down. Then, using the left mouse button, the user will select a pair of cards to flip over. If the two cards match, the user leaves them face up. If the two cards do not match, the user can flip either one or both cards face down. The user then selects one card to match with the card left face up or selects a pair of cards if s/he turned the two cards in the previous pair down. The game will continue until all cards are face up. At that stage, you may display an info dialog box telling the user that the game is over.
Development Hints and Remarks
Study the Blackjack case study from Chapter 8.
Study the cards demo case study for viewing images of playing cards from Chapter 9.
Use labels to display PhotoImage objects associated with card images.
When creating a PhotoImage object, make sure to keep a reference to the image object to prevent it from being garbage collected by Python's memory allocator. It cannot be a local variable as local variables are destroyed at the end of function/method execution. You can use a global variable or an instance attribute to hold all PhotoImage objects.
You may find this code useful:
The event handler for <Button-1> needs to know which label was clicked to change the value of its image attribute. One way to do this is to access the widget attribute of the event object. An easier method is to pass extra parameter(s) to the event handler in addition to the event attribute. One way of doing this is to use a lambda function with default values for the additional attributes as done in the sample program
Explanation / Answer
# implementation of card game - Memory
import simplegui
import random
import math
WIDTH = 400
HEIGHT = 400
started = False
class ImageInfo:
def __init__(self, center, size, radius = 0, lifespan = None, animated = False):
self.center = center
self.size = size
self.radius = radius
if lifespan:
self.lifespan = lifespan
else:
self.lifespan = float('inf')
self.animated = animated
def get_center(self):
return self.center
def get_size(self):
return self.size
# load card
CARD_SIZE = (72, 96)
CARD_CENTER = (36, 48)
# splash image
splash_info = ImageInfo([200, 150], [400, 300])
splash_image = simplegui.load_image("")
card_images = simplegui.load_image("")
card_back = simplegui.load_image("")
# define constants for card game
PAIRS = 12
LINES = 4
REAL_SIZE = (70, 100)
REAL_CENTER = (35, 50)
TEXT_SIZE = 75
TEXT_CORNER = (15, 75)
# helper function to initialize globals
def new_game():
global cards, exposed, pickup, state, counter
global suit_idx, back_idx
cards = range(0, PAIRS)
cards.extend(cards)
random.shuffle(cards)
exposed = [False] * len(cards)
pickup = [None, None]
state = 0
counter = 0
label.set_text("Turns = " + str(counter))
suit_idx = random.randrange(0, 4)
back_idx = random.randrange(0, 2)
# define event handlers
def mouseclick(pos):
global state, counter, started
center = [WIDTH / 2, HEIGHT / 2]
size = splash_info.get_size()
inwidth = (center[0] - size[0] / 2) < pos[0] < (center[0] + size[0] / 2)
inheight = (center[1] - size[1] / 2) < pos[1] < (center[1] + size[1] / 2)
if (not started) and inwidth and inheight:
started = True
# flip cards based on the location of the mouse click
flip = None
for idx in range(0, len(cards)):
if not exposed[idx]:
row = idx // LINES
col = idx % LINES
if pos[0] >= REAL_SIZE[0]*row and pos[0] < REAL_SIZE[0]*(row+1) and
pos[1] >= REAL_SIZE[1]*col and pos[1] < REAL_SIZE[1]*(col+1):
exposed[idx] = True
flip = idx
# select two cards and determin if they match
if flip in range(0, len(cards)):
if state == 0:
state = 1
elif state == 1:
state = 2
else:
state = 1
# determine if the previous two cards are unpaired
if cards[pickup[0]] != cards[pickup[1]]:
exposed[pickup[0]] = False
exposed[pickup[1]] = False
pickup[state-1] = flip
if state == 1:
pickup[state] = None
counter += 1 # keeps track of the number of turns
label.set_text("Turns = " + str(counter))
# cards are logically (REAL_SIZE[0], REAL_SIZE[1]) pixels in size
def draw(canvas):
global started
for idx, card in enumerate(cards):
row = idx // LINES
col = idx % LINES
border = [(REAL_SIZE[0]*row, REAL_SIZE[1]*col),
(REAL_SIZE[0]*(row+1), REAL_SIZE[1]*col),
(REAL_SIZE[0]*(row+1), REAL_SIZE[1]*(col+1)),
(REAL_SIZE[0]*row, REAL_SIZE[1]*(col+1))]
if exposed[idx]:
if idx in pickup:
text_color = 'Red'
else:
text_color = 'White'
if frame.get_canvas_textwidth(str(card), TEXT_SIZE) * 2 > TEXT_SIZE:
text_size = TEXT_SIZE // 2
else:
text_size = TEXT_SIZE
text_loc = (TEXT_CORNER[0] + REAL_SIZE[0] * row, TEXT_CORNER[1] + REAL_SIZE[1] * col)
canvas.draw_polygon(border, 1, 'White')
canvas.draw_text(str(card), text_loc, text_size, text_color)
# draw card image
card_loc = (CARD_CENTER[0] + CARD_SIZE[0] * card, CARD_CENTER[1] + CARD_SIZE[1] * suit_idx)
real_loc = (REAL_CENTER[0] + REAL_SIZE[0] * row, REAL_CENTER[1] + REAL_SIZE[1] * col)
canvas.draw_image(card_images, card_loc, CARD_SIZE, real_loc, REAL_SIZE)
else:
canvas.draw_polygon(border, 1, 'White', 'Green')
# draw card background
card_loc = (CARD_CENTER[0] + CARD_SIZE[0] * back_idx, CARD_CENTER[1])
real_loc = (REAL_CENTER[0] + REAL_SIZE[0] * row, REAL_CENTER[1] + REAL_SIZE[1] * col)
canvas.draw_image(card_back, card_loc, CARD_SIZE, real_loc, REAL_SIZE)
if not started:
canvas.draw_image(splash_image, splash_info.get_center(),
splash_info.get_size(), [WIDTH / 2, HEIGHT / 2],
splash_info.get_size())
# create frame and add a button and labels
frame = simplegui.create_frame("Memory", REAL_SIZE[0] * math.ceil(PAIRS*2.0/LINES), REAL_SIZE[1] * LINES)
frame.add_button("Reset", new_game)
label = frame.add_label("Turns = 0")
# register event handlers
frame.set_mouseclick_handler(mouseclick)
frame.set_draw_handler(draw)
# get things rolling
new_game()
frame.start()
NOTE: Please include full web address of an online image in the program for splash_image, card_images and card back from assignment in order for this piece of code to run.
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.