How to make a memory game using tkinter.

How to make a memory game using tkinter.

·

6 min read

Memory game are fun to play and easy to make.
Here's how I made mine using tkinter in python.

How the game will be like

  • There will be some buttons with numbers from 0 to a number n-1
  • There are 25 chances
  • On clicking, the buttons reveal their numbers
  • When two buttons are clicked, if their numbers are same, they become disabled and a label shows that it is a match
  • Else, a messagebox shows that it is incorrect and both numbers disappear
  • When all the numbers are correct it shows you won
  • When all the chances are over it shows you lose
  • There is a menu bar with the options to quit game and reset game

Completed.png A completed game

Wrong.png When The player gets it wrong

How the game works

  • When a tile is clicked, its text is changed to the corresponding number in a list of matches
  • The program stores this tile's index in a list called answer_list
  • When a second tile is clicked, the following happens:
    • The program adds the second tile's index also to the answer_list
    • The program checks if both tiles' corresponding values in matches are equal
    • Depending on whether they are equal or not, do the respective
    • Empty the answer_list as two buttons have been clicked

Starting with the window

All this code is the same for most tkinter projects

from tkinter import *
from tkinter import messagebox

root = Tk()
root.mainloop() #This line is always at the end of the program

Defining the global variables

won = False
count = 0
answer_list = []

Making a list of all the matches

Here we will use a variable called NUMBER which stores the number of unique tiles
Using list comprehension, we will make a list of all the matches twice (because there have to be two of the same number) and the shuffle the list

from random import shuffle

NUMBER = 10 #We will be having ten unique tiles for this example but you can change this
matches = [x for x in range(NUMBER) for _ in range(2)]
shuffle(matches)

Creating the tiles and adding them to the screen

First a frame for all the tiles to be contained in

my_frame = Frame(root) #Frame for all the tiles
my_frame.pack()

Then, a list containing all the tiles

tiles = []
    for i in range(len(matches)):
        tiles.append(Button(
            my_frame,
            text = ' ', 
            font = ("Helvetica", 40),
            height =1, width = 3,
            command = lambda i=i: onclick(i))) #The onclick function will be shown later

Now comes the tricky part. We need to arrange the tiles in such a way that the columns and rows are factors of the total number of tiles. I have made a function to do that. This will work for any composite number of tiles, and since our number of tiles are double of the unique tiles, we know that it will always be even (and thus by extension composite).

from math import sqrt

def find_rows_cols(number):
    max_cols = int(sqrt(number))
    for i in range(max_cols, 0, -1):
        if number % i == 0:
            cols = i
            break
    rows = int(number/cols)
    return rows, cols

Now, we add the tiles to the my_frame we made before

rows, cols = find_rows_cols(len(tiles))
#Adding the tiles to screen
for i,tile in enumerate(tiles):
    row = i%cols
    col = int(i/cols)
    tile.grid(row= row, column = col)

Defining the onclick function

First, We need to define a label in which we will show whether it was wrong or right. By default it shows how many chances you have left

label = Label(root, text= f"{chances = }", font= ("Helvetica", 30))
label.pack()

To change the text of the tile when it is clicked

def onclick(index):
    global answer_list, label, won, NUMBER, tiles, chances, tiles
    label["text"] = f'{chances = }'

    if tiles[index]["text"] == ' ': #If the tile has been clicked 
        tiles[index]["text"] = matches[index]
        answer_list.append(index)

    else: #If it has not been clicked
        tiles[index]["text"] = ' '
        answer_list = []

Now, we have to get to the points part.
The following code occurs when two tiles have been clicked and both those tiles' corresponding items in the matches list are equal.


    if len(answer_list) == 2: # If two tiles have been clicked
        if matches[answer_list[0]] == \
            matches[answer_list[1]]:
            tiles[answer_list[0]]["state"] = DISABLED #Disabling both buttons
            tiles[answer_list[1]]["state"] = DISABLED
            label["text"] = f"It's a Match! {chances = }"
            won += 1

            if won == NUMBER:
                label["text"] = "You Won!"

Now, we even need to add in the code for what happens when they are not equal

else:
            chances -= 1
            label["text"] = f"Ahhh try again {chances = }"
            messagebox.showinfo("Incorrect", "Incorrect")

            tiles[answer_list[0]]["text"] = ' '
            tiles[answer_list[1]]["text"] = ' '

Emptying the answer_list

answer_list = []

Finally, to add what happens when the chances become zero

if chances == 0:
        for tile in tiles:
            tile["state"] = DISABLED
        label["text"] = "You Lost D:"

After all this, our onclick function is huge. Here is the complete code for the onclick funtion

def onclick(index):
    global answer_list, label, won, NUMBER, tiles, chances, tiles
    label["text"] = f'{chances = }'

    if tiles[index]["text"] == ' ': #If the tile has been clicked 
        tiles[index]["text"] = matches[index]
        answer_list.append(index)

    else: #If it has not been clicked
        tiles[index]["text"] = ' '
        answer_list = []

    if len(answer_list) == 2: # If two tiles have been clicked
        if matches[answer_list[0]] == \
            matches[answer_list[1]]:
            tiles[answer_list[0]]["state"] = DISABLED
            tiles[answer_list[1]]["state"] = DISABLED
            label["text"] = f"It's a Match! {chances = }"
            won += 1
            if won == NUMBER:
                label["text"] = "You Won!"
        else:
            chances -= 1
            label["text"] = f"Ahhh try again {chances = }"
            messagebox.showinfo("Incorrect", "Incorrect")

            tiles[answer_list[0]]["text"] = ' '
            tiles[answer_list[1]]["text"] = ' '

        answer_list = []

    if chances == 0:
        for tile in tiles:
            tile["state"] = DISABLED
        label["text"] = "You Lost D:"

Adding a options menu


my_menu = Menu(root)
root.config(menu=my_menu)

# Create an Options Dropdown Menu
option_menu = Menu(my_menu, tearoff=False)
my_menu.add_cascade(label="Options", menu=option_menu)
option_menu.add_command(label="Reset Game", command=reset)
option_menu.add_separator()
option_menu.add_command(label="Exit Game", command=root.quit)

Finally, to define the reset function for the board to be reset when the menu resets

def reset():
    global matches, won, tiles, chances
    chances = 25
    won = False
    shuffle(matches)

    #Reset Label
    label["text"] = ' '

    tiles = [] #Making the `tiles` list from scratch
    for i in range(len(matches)): 
        tiles.append(Button(my_frame, text = ' ', 
            font = ("Helvetica", 40), height =1, width = 3,
            command = lambda i=i: onclick(i)))

    rows, cols = find_rows_cols(len(tiles))
    for i in range(len(tiles)): #Positioning the tiles the same way we did before
        row = i%cols
        col = int(i/cols)
        tiles[i].grid(row= row, column = col)

Hooray! You have made the game.
Entire code for game: %[github.com/VasTheCoder/Miscellaneous-Projec..