Python Memory Game Source Code

How To Create Memory Game in Python Using Tkinter

How To Create Memory Game in Python Using Tkinter


In this Python Tutorial we will see How to Create a Memory Game (card-matching game) with smooth animations, multiple difficulty levels, and a dark theme interface.

The Game Features:
- Multiple Difficulty Levels: 4x4 (16 cards, 8 pairs), 4x5 (20 cards, 10 pairs), and 5x6 grid sizes (30 cards, 15 pairs).
Card Matching: Automatic pair detection.
Move counter and timerThe game tracks moves, elapsed time, and provides detailed performance statistics.

What We Are Gonna Use In This Project:

- Python Programming Language.
- VS Editor.




if you want the source code click on the download button below




Project Source Code:


    
     - Create frame for cards.
     

def create_game_grid(self):
# Create frame to hold all cards
self.cards_frame = tk.Frame(self.game_frame, bg=self.colors['bg'])
# Center the grid in the game area
self.cards_frame.pack(expand=True)

# Initialize cards list and get symbol pairs
self.cards = [] # Empty list to store card widgets

# Get grid dimensions for current difficulty
rows, cols = self.difficulty_levels[self.current_difficulty]["grid"]
# Double the symbols list for pairs
symbols = self.difficulty_levels[self.current_difficulty]["symbols"] * 2

# Randomly shuffle symbols to place them on the grid
random.shuffle(symbols)
# Store shuffled symbols for later reference
self.symbols = symbols

# Create cards in grid
for i in range(rows): # Loop through each row
for j in range(cols): # Loop through each column in current row
card_idx = i*cols+j # Calculate linear index from row and column

# Create card canvas
# Create canvas with fixed size And Set background And remove border
card = tk.Canvas(self.cards_frame, width=80, height=100,
bg=self.colors['card_bg'], highlightthickness=0)
# Position card in grid with spacing
card.grid(row=i, column=j, padx=5, pady=5)
# Bind click event
card.bind("<Button-1>", lambda e, idx=card_idx: self.on_card_click(idx))

# Create card back (visible initially)
# Create card shape And Add colored border
card.create_rectangle(5, 5, 75, 95, fill=self.colors['card_bg'],
outline=self.colors['card_fg'], width=2)
# Add question mark and Set text color
card.create_text(40, 50, text="?", font=("Helvetica", 24, "bold"),
fill=self.colors['card_fg'])

# Create card front (hidden initially)
# Create card shape
# Add colored border
# Hide initially and add tag for later reference
card.create_rectangle(5, 5, 75, 95, fill=self.colors['card_fg'],
outline=self.colors['card_bg'], width=2,
state='hidden', tags=('front',))
# Add symbol text
# Use bold font for symbol
# Set text color
# Hide initially and add tag
card.create_text(40, 50, text=self.symbols[card_idx],
font=("Helvetica", 24, "bold"),
fill=self.colors['card_bg'],
state='hidden', tags=('symbol',))

self.cards.append(card) # Add card to list for later reference



    
     - Handles click events on cards.
     

def on_card_click(self, idx):
# Start timer on first click
if self.start_time is None: # If this is the first click of the game
self.start_time = time.time() # Record start time
self.update_time() # Start timer updates

# Ignore invalid clicks
if idx in self.revealed or idx in self.matched_cards or len(self.revealed) == 2:
# Skip if card is already revealed, matched, or 2 cards are already flipped
return

# Reveal the clicked card
self.reveal_card(idx) # Show the card face
self.revealed.append(idx) # Add to list of revealed cards

# If two cards are revealed, check for a match
if len(self.revealed) == 2: # When two cards have been flipped
self.moves += 1 # Increment move counter
self.moves_label.config(text=f"Moves: {self.moves}") # Update moves display
self.master.after(500, self.check_match) # schedule match check after a delay


    
    
     - Reveal and Hide Cards


def reveal_card(self, idx):
card = self.cards[idx] # Get the card canvas widget
card.itemconfig('front', state='normal') # Show the card front
card.itemconfig('symbol', state='normal') # Show the symbol

def hide_card(self, idx):
card = self.cards[idx] # Get the card canvas widget
card.itemconfig('front', state='hidden') # Hide the card front
card.itemconfig('symbol', state='hidden') # Hide the symbol



     - Method to check for a match between flipped cards.


def check_match(self):
idx1, idx2 = self.revealed # Get indices of the two revealed cards
if self.symbols[idx1] == self.symbols[idx2]: # If symbols match
# Match found
self.matched_pairs += 1 # Increment matched pairs counter
self.matched_cards.extend([idx1, idx2]) # Add both cards to matched list

# Highlight matched cards
for idx in [idx1, idx2]: # For each matched card
card = self.cards[idx] # Get card widget
# Change to green color to indicate match
card.itemconfig('front', fill="#8bc34a")

# Check if game is over
if self.matched_pairs == len(self.symbols) // 2: # If all pairs are found
# Schedule game over screen after delay
self.master.after(500, self.game_over)

else: # If symbols don't match
# No match
self.hide_card(idx1) # Flip first card back
self.hide_card(idx2) # Flip second card back
self.revealed.clear() # Clear the revealed cards list for next move


    
     - Start a New Game.

def new_game(self):
# Reset game state
self.game_solved = False # Reset game solved flag
self.revealed.clear() # Clear revealed cards list
self.matched_cards.clear() # Clear matched cards list
self.matched_pairs = 0 # Reset matched pairs counter
self.moves = 0 # Reset moves counter
self.start_time = None # Reset start time

# Reset labels
self.moves_label.config(text="Moves: 0") # Reset moves display
self.time_label.config(text="Time: 0:00") # Reset time display

# Recreate the game grid
self.cards_frame.destroy() # Remove old card grid
self.create_game_grid() # Create new shuffled grid


    

     - Method to display the congratulations dialog when the game is won.


def game_over(self):
self.game_solved = True # Mark game as completed
elapsed_time = int(time.time() - self.start_time) # Calculate total game time
minutes, seconds = divmod(elapsed_time, 60) # Convert to minutes and seconds

# Create game over window
game_over_window = tk.Toplevel(self.master) # Create new popup window
game_over_window.title("Game Over") # Set window title
game_over_window.geometry("350x350") # Set window size
game_over_window.configure(bg=self.colors['gameover_bg']) # Set background
game_over_window.grab_set() # Make window modal
game_over_window.transient(self.master) # Set as transient to main window

# Center the game over window on screen
x = self.master.winfo_x() + (self.master.winfo_width() // 2) - (350 // 2)
y = self.master.winfo_y() + (self.master.winfo_height() // 2) - (350 // 2)
game_over_window.geometry(f"+{x}+{y}")

# Create congratulations label
tk.Label(game_over_window, text="Congratulations!",
font=("Helvetica", 28, "bold"),
bg=self.colors['gameover_bg'], fg=self.colors['text']).pack(pady=(20, 30))

# Create stats frame
stats_frame = tk.Frame(game_over_window, bg=self.colors['gameover_bg'])
stats_frame.pack(pady=(0, 30)) # Add padding below frame

# Display stats
        # Show difficulty level
self.create_stat_label(stats_frame, "Difficulty", self.current_difficulty)
        # Show total moves
self.create_stat_label(stats_frame, "Moves", str(self.moves))
        # Show total time
self.create_stat_label(stats_frame, "Time", f"{minutes}:{seconds:02d}")
# Play again button
play_again_button = tk.Button(game_over_window, text="Play Again",
font=self.custom_font,
bg=self.colors['button_bg'], fg=self.colors['button_fg'],
relief=tk.FLAT,
command=lambda: [game_over_window.destroy(), self.new_game()])
play_again_button.pack(pady=20) # Add padding around button

# Add hover effect to play again button
play_again_button.bind("<Enter>",
            lambda e: e.widget.config(bg="#5dbb5e")) # Lighten on hover
play_again_button.bind("<Leave>",
            lambda e: e.widget.config(bg=self.colors['button_bg'])) # Restore on leave




The Final Result:

Python Memory Game Source Code

Python Memory Game

Python Memory Game Using Tkinter


if you want the full source code click on the download button below




disclaimer: you will get the source code, and to make it work in your machine is your responsibility and to debug any error/exception is your responsibility this project is for the students who want to see an example and read the code not to get and run.





JavaScript Puzzle Game Source Code

How To Create Image Puzzle Game in JavaScript

How To Create Image Puzzle Game in JavaScript


In this JavaScript Tutorial we will see How to Create a puzzle game using JavaScript With HTML and CSS.
Players can choose an image and select from 5 different difficulty levels (4x4 to 8x8 grids) and compete against time while tracking their moves.

The Game Features:
- Dynamically slice any uploaded image into puzzle pieces.
Multiple difficulty levels from beginner-friendly 4x4 grids to challenging 8x8 grids with 64 pieces. .
Move counter and timer.
Smooth piece-swapping animations.
- Winning detection and celebration.

What We Are Gonna Use In This Project:

- JavaScript Programming Language.
- HTML and CSS.
- Visual Studio Editor.




if you want the source code click on the download button below




Project Source Code:



     - Image Slicer and Randomizer.


/**
* Slices the image into pieces and randomizes their positions
* @param {Image} image - The image to slice into puzzle pieces
*/
function sliceAndRandomizeImage(image) {

// Get the container for puzzle pieces
const sliceContainer = document.getElementById('sliceContainer');
sliceContainer.innerHTML = ''; // Clear previous puzzle pieces

// Create a temporary canvas to work with the image
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

const displaySize = 600; // Fixed size for the displayed image

canvas.width = displaySize;
canvas.height = displaySize;

// Draw the image onto the canvas, scaling it to our fixed size
ctx.drawImage(image, 0, 0, displaySize, displaySize);

const slices = []; // Array to hold all puzzle pieces

// Calculate dimensions of each puzzle piece
const sliceWidth = canvas.width / sliceCount;
const sliceHeight = canvas.height / sliceCount;

// Create individual puzzle pieces
for (let row = 0; row < sliceCount; row++) {
for (let col = 0; col < sliceCount; col++) {

// Create a canvas for each puzzle piece
const sliceCanvas = document.createElement('canvas');
const sliceCtx = sliceCanvas.getContext('2d');
sliceCanvas.width = sliceWidth;
sliceCanvas.height = sliceHeight;

// Draw the corresponding portion of the original image
sliceCtx.drawImage(
canvas,
col * sliceWidth, row * sliceHeight, sliceWidth, sliceHeight,//source
0, 0, sliceWidth, sliceHeight // destination rectangle
);

// Create an image from the slice canvas
const sliceImg = document.createElement('img');
sliceImg.src = sliceCanvas.toDataURL();

// Create the div element that will contain the image
const sliceDiv = document.createElement('div');
sliceDiv.className = 'slice';
sliceDiv.appendChild(sliceImg);

// Store original position data
sliceDiv.dataset.row = row;
sliceDiv.dataset.col = col;

// Add click event to the slice
sliceDiv.addEventListener('click', function() {
onSliceClick(sliceDiv);
});

slices.push(sliceDiv);

}
}

// Randomize the order of slices
shuffleArray(slices);

// Add all puzzle pieces to the container
slices.forEach(slice => {
sliceContainer.appendChild(slice);
});

// Update the grid layout based on the current level
sliceContainer.style.gridTemplateColumns = `repeat(${sliceCount}, 1fr)`;

// Reset the move count
moveCount = 0;
document.getElementById('moveCount').textContent = moveCount;

}




     -Array Shuffler (Fisher-Yates Algorithm). 


/**
* Shuffles array elements randomly (Fisher-Yates algorithm)
* @param {Array} array - The array to shuffle
*/
function shuffleArray(array) {

// Loop through array from end to beginning
for (let i = array.length - 1; i > 0; i--) {

// Pick a random element from 0 to i
const j = Math.floor(Math.random() * (i + 1));
// Swap elements i and j
[array[i], array[j]] = [array[j], array[i]];

}

}




     - Slice Click Handler, Manages puzzle piece selection and swapping.


/**
* Handles click events on puzzle pieces
* @param {HTMLElement} slice - The clicked puzzle piece
*/
function onSliceClick(slice) {
// If no piece is currently selected, select this one
if (firstSelectedSlice === null) {
firstSelectedSlice = slice;
slice.classList.add('selected'); // Highlight the selected piece
}
else{
// If a piece is already selected, swap it with the current one
const secondSelectedSlice = slice;

// Don't count clicking the same piece twice as a move
if (firstSelectedSlice === secondSelectedSlice) {
firstSelectedSlice.classList.remove('selected');
firstSelectedSlice = null;
return;
}

// Swap the two selected pieces
swapSlices(firstSelectedSlice, secondSelectedSlice);
firstSelectedSlice.classList.remove('selected');
firstSelectedSlice = null;

// Increment move counter and update display
moveCount++;
document.getElementById('moveCount').textContent = moveCount;

// Check if puzzle is complete after the swap
checkPuzzleComplete();
}

}

    


     - Determines if the puzzle is solved.


/**
* Checks if the puzzle is completed (all pieces in correct position)
*/
function checkPuzzleComplete() {

const slices = document.querySelectorAll('.slice');
let isComplete = true;

// Check each piece's current position against its original position
for (let i = 0; i < slices.length; i++) {
// Calculate where this piece should be in a completed puzzle
const row = Math.floor(i / sliceCount);
const col = i % sliceCount;

// If any piece is out of place, puzzle is not complete
if (slices[i].dataset.row != row || slices[i].dataset.col != col) {
isComplete = false;
break;
}
}

// If puzzle is complete, show completion modal
if (isComplete) {
stopTimer();
//showPuzzleCompleteModal();

// Show modal after 3 seconds
setTimeout(() => {
showPuzzleCompleteModal();
}, 3000); // 1000 milliseconds = 3 seconds

}

}




     - Animates the exchange of two puzzle pieces.


/**
* Swaps two puzzle pieces with animation
* @param {HTMLElement} slice1 - First puzzle piece
* @param {HTMLElement} slice2 - Second puzzle piece
*/
function swapSlices(slice1, slice2) {

// Add animation class
slice1.classList.add('swapping');
slice2.classList.add('swapping');

// Get parent and position references
const parent = slice1.parentNode;
const sibling = slice1.nextSibling === slice2 ? slice1 : slice1.nextSibling;

// Swap the DOM elements
slice2.parentNode.insertBefore(slice1, slice2);
parent.insertBefore(slice2, sibling);

// Remove animation class after animation completes
setTimeout(() => {
slice1.classList.remove('swapping');
slice2.classList.remove('swapping');
}, 600);

}

    


     - Start, Stop and Update the Timer.


/**
* Starts the game timer
*/
function startTimer() {
stopTimer(); // Clear any existing timer
seconds = 0;
timer = setInterval(updateTimer, 1000);
}

/**
* Stops the game timer
*/
function stopTimer() {
clearInterval(timer);
}

/**
* Updates the timer display every second
*/
function updateTimer() {

seconds++;
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;

// Format time as MM:SS
document.getElementById('timer').textContent =
`${minutes.toString().padStart(2, '0')}:
                            ${remainingSeconds.toString().padStart(2, '0')}`;

}





     - Shows the victory screen with statistics.


/**
* Shows the puzzle completion modal with stats
*/
function showPuzzleCompleteModal() {

const modal = document.getElementById('puzzleCompleteModal');

// Display completion stats
document.getElementById('completedLevel').textContent = level;
document.getElementById('completionTime').textContent =
                            document.getElementById('timer').textContent;
document.getElementById('completionMoves').textContent = moveCount;

modal.style.display = 'block';

}




     - Restores the game to its initial state.


/**
* Resets the game state
*/
function resetGame() {

// If an image has been selected, re-slice it
const fileInput = document.getElementById('fileInput');

if (fileInput.files.length > 0) {

const file = fileInput.files[0];
const reader = new FileReader();

reader.onload = function(e) {

const img = new Image();
img.src = e.target.result;

img.onload = function() {
sliceAndRandomizeImage(img);
startTimer();
}

}

reader.readAsDataURL(file);

}

// Update level display
document.getElementById('level').textContent = level;
moveCount = 0;
document.getElementById('moveCount').textContent = moveCount;

}





The Final Result:

JavaScript Puzzle Game Source Code

JavaScript Puzzle Game

Puzzle Game In JavaScript



if you want the source code click on the download button below




disclaimer: you will get the source code, and to make it work in your machine is your responsibility and to debug any error/exception is your responsibility this project is for the students who want to see an example and read the code not to get and run.