How to make a Macthing Pair game with Pygame

Today we start with our vacation free games offering to start learning python making games. Let’s start soon with this one: matching.py, a very simple, but also very nice game to pass your time and to improve your memory. The code will be effective, simple, well explained.
Let’s start.

Show some colors

import random
import pygame

# Scheme of the cards 8x8 = 64
# We will put the cards into this grid
lyt = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
]

status = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
]
# the cards num, the different cards num and col and row

colors = (0,0,0)

# Cards will have different random colors
# you have to find the same colored ones
cards_colors = []
for n in range(32):
	a = random.randrange(0, 255)
	b = random.randrange(0, 255)
	c = random.randrange(0, 255)
	cards_colors.append([a, b, c])

# Duplicate cards and shuffle order
cards_colors.extend(cards_colors)
random.shuffle(cards_colors)
print(cards_colors)

# Now we have a grid with the colors
lyt_col = []
ncards = 0 # counter for cards_colors
for nrow, row in enumerate(lyt):
	for ncol, col in enumerate(row):
		lyt[nrow][ncol] = cards_colors[ncards]
		# Create the tile with the color
		surf = pygame.Surface((64,64))
		surf.fill(cards_colors[ncards])
		lyt_col.append(surf)
		ncards += 1
print("_"*10, "\n", *lyt, sep="\n")


pygame.init()
card_num = 64
couples = 32
cols, rows = (8,8)
tile_size = 64
size = cols*tile_size, rows*tile_size 
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()

def draw_screen():
	ncards = 0 # counter for cards_colors
	for nrow, row in enumerate(lyt):
		for ncol, col in enumerate(row):
			screen.blit(lyt_col[ncards], (ncol*64, nrow*64))
			ncards += 1

loop = 1
while loop:
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			loop = 0
	draw_screen()
	clock.tick(60)
	pygame.display.flip()


pygame.quit()

Now we created a grid with a lot of color, like this:

The fundation of the game… and it’s colorful

There is no need of images. All the code is in one file. Almost self explanatory.

Now we want to click on these colors and if we get the same couples, those ones will be deleted. This is not the purpose of the game, because it would be too easy. But we want to make this step before hiding the tiles, so that is all very simple. Remember to imagine always solutions that make coding simple and straight.

Let’s make it a little more “classy” (terrible word pun, sorry.,,)

It’s the same code, but organized in 2 classes.

import random
import pygame

class Generator:
	def __init__(self):
		self.lyt = [
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,]
		]

		ncells = len(self.lyt)*len(self.lyt[0])
		print(f"{ncells=}")
		clrs = []
		self.populate_color()
		# print(self.lyt)
		# print(self.lyt_surfaces)

	def clr(self):
		return random.randrange(0, 255, 10)
	
	def populate_color(self):
		''' creates 32 random color + 32 like the first 32 '''
		for r, line in enumerate(self.lyt):
			for c, x in enumerate(line):
				color = [self.clr(), self.clr(), self.clr()]
				self.lyt[r][c] = color
				# surf = pygame.Surface((64,64))
				# surf.fill(color)
				# self.lyt_surfaces.append(surf)
		self.lyt_surfaces = [] # contains surfaces

		random.shuffle(self.lyt)
		self.lyt[:4] = self.lyt[4:9]
		for r, line in enumerate(self.lyt):
			for c, x in enumerate(line):
				color = self.lyt[r][c]
				surf = pygame.Surface((64,64))
				surf.fill(color)
				self.lyt_surfaces.append(surf)
		



class Win:
	def __init__(self):
		pygame.init()
		card_num = 64
		couples = 32
		cols, rows = (8,8)
		tile_size = 64
		size = cols*tile_size, rows*tile_size 
		self.screen = pygame.display.set_mode(size)
		self.clock = pygame.time.Clock()
		self.game_loop()

	def draw_screen(self):
		ncards = 0 # counter for cards_colors
		for nrow, row in enumerate(grid.lyt):
			for ncol, col in enumerate(row):
				self.screen.blit(grid.lyt_surfaces[ncards], (ncol*64, nrow*64))
				ncards += 1

	def game_loop(self):
		loop = 1
		while loop:
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					loop = 0
				if event.type == pygame.MOUSEBUTTONDOWN:
					x, y = pygame.mouse.get_pos()
					col, row = x//64,  y//64
					print(row, col)
					print(grid.lyt[row][col])
			self.draw_screen()
			self.clock.tick(60)
			pygame.display.flip()
		pygame.quit()




grid = Generator()
# print(grid.lyt_surfaces)
Win()

A working code, still raw though

Every works, still need some work though.

import random
import pygame

class Generator:
	def __init__(self):
		self.lyt = [
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,]
		]

		ncells = len(self.lyt)*len(self.lyt[0])
		print(f"{ncells=}")
		clrs = []
		self.populate_color()
		# print(self.lyt)
		# print(self.lyt_surfaces)

	def clr(self):
		return random.randrange(0, 255, 10)
	
	def populate_color(self):
		''' creates 32 random color + 32 like the first 32 '''
		for r, line in enumerate(self.lyt):
			for c, x in enumerate(line):
				color = [self.clr(), self.clr(), self.clr()]
				self.lyt[r][c] = color
				# surf = pygame.Surface((64,64))
				# surf.fill(color)
				# self.lyt_surfaces.append(surf)
		self.lyt_surfaces = [] # contains surfaces
		self.lyt[:4] = self.lyt[4:9]
		self.shuffle_colors()
		self.set_surfaces()

	def shuffle_colors(self):
		for n, line in enumerate(self.lyt):
			self.lyt[n] = random.sample(line, len(line))
		random.shuffle(self.lyt)
		print(*self.lyt, sep="\n")

	def set_surfaces(self):
		for r, line in enumerate(self.lyt):
			row_clr = []
			for c, color in enumerate(line):
				surf = pygame.Surface((64,64))
				surf.fill(color)
				row_clr.append(surf)
			self.lyt_surfaces.append(row_clr)
		# print(self.lyt_surfaces)
		



class Win:
	def __init__(self):
		pygame.init()
		self.snd_win = pygame.mixer.Sound("sounds\\win.wav")
		self.snd_click = pygame.mixer.Sound("sounds\\click.ogg")
		self.snd_whip = pygame.mixer.Sound("sounds\\whip.ogg")
		card_num = 64
		couples = 32
		cols, rows = (8,8)
		tile_size = 64
		size = cols*tile_size, rows*tile_size 
		self.screen = pygame.display.set_mode(size)
		self.clock = pygame.time.Clock()
		self.game_loop()

	def draw_screen(self):
		for nrow, row in enumerate(grid.lyt_surfaces):
			for ncol, col in enumerate(row):
				self.screen.blit(col, (ncol*64, nrow*64))


	def game_loop(self):
		loop = 1
		count_taken = 0
		score = 0
		while loop:
			if score == 32:
				print("YOU WIN!")
				pygame.mixer.Sound.play(self.snd_win)
				pygame.mixer.Sound.play(self.snd_win)
				pygame.mixer.Sound.play(self.snd_win)
				loop = 0
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					loop = 0
				if event.type == pygame.MOUSEBUTTONDOWN:
					x, y = pygame.mouse.get_pos()
					col, row = x//64,  y//64

					if grid.lyt[row][col] != [0,0,0]:
						pygame.mixer.Sound.play(self.snd_click)
						print(grid.lyt[row][col])
						count_taken += 1
						print(f"{count_taken=}")
						if count_taken == 1 :
							first = grid.lyt[row][col]
							r1, c1 = row, col
						elif count_taken == 2:
							second = grid.lyt[row][col]
							r2, c2 = row, col
							if (r2, c2) != (r1, c1):
								print(r2, c2, "-", r1, c1)
								if first == second:
									print("Hai trovato una coppia")
									score += 1
									pygame.mixer.Sound.play(self.snd_win)
									count_taken = 0
									grid.lyt_surfaces[r1][c1].fill((0,0,0))
									grid.lyt[r1][c1] = [0,0,0]
									grid.lyt_surfaces[r2][c2].fill((0,0,0))
									grid.lyt[r2][c2] = [0,0,0]
									grid.set_surfaces()
								else:
									print("Sono diversi")
									count_taken = 0
									pygame.mixer.Sound.play(self.snd_whip)
							else:
								print("Devi cliccare su un'altra casella")
								pygame.mixer.Sound.play(self.snd_whip)
								count_taken = 0


					print(row, col)
			self.draw_screen()
			self.clock.tick(60)
			pygame.display.flip()
		pygame.quit()




grid = Generator()
# print(grid.lyt_surfaces)
Win()

Let’s add some sounds and particles to make it more nice

import random
import pygame
import winsound

frequency = 2500  # Set Frequency To 2500 Hertz
duration = 100  # Set Duration To 1000 ms == 1 second



class Generator:
	def __init__(self):
		self.lyt = [
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,]
		]

		ncells = len(self.lyt)*len(self.lyt[0])
		print(f"{ncells=}")
		clrs = []
		self.populate_color()
		# print(self.lyt)
		# print(self.lyt_surfaces)

	def clr(self):
		return random.randrange(0, 255, 10)
	
	def populate_color(self):
		''' creates 32 random color + 32 like the first 32 '''
		for r, line in enumerate(self.lyt):
			for c, x in enumerate(line):
				color = [self.clr(), self.clr(), self.clr()]
				self.lyt[r][c] = color
				# surf = pygame.Surface((64,64))
				# surf.fill(color)
				# self.lyt_surfaces.append(surf)
		self.lyt_surfaces = [] # contains surfaces
		self.lyt[:4] = self.lyt[4:9]
		self.shuffle_colors()
		self.set_surfaces()

	def shuffle_colors(self):
		for n, line in enumerate(self.lyt):
			self.lyt[n] = random.sample(line, len(line))
		random.shuffle(self.lyt)
		print(*self.lyt, sep="\n")

	def set_surfaces(self):
		for r, line in enumerate(self.lyt):
			row_clr = []
			for c, color in enumerate(line):
				surf = pygame.Surface((64,64))
				surf.fill(color)
				row_clr.append(surf)
			self.lyt_surfaces.append(row_clr)
		# print(self.lyt_surfaces)
		


class Win:
	def __init__(self):
		pygame.init()

		# self.snd_win = pygame.mixer.Sound("sounds\\win.wav")
		# self.snd_click = pygame.mixer.Sound("sounds\\click.ogg")
		# self.snd_whip = pygame.mixer.Sound("sounds\\whip.ogg")
		card_num = 64
		couples = 32
		cols, rows = (8,8)
		tile_size = 64
		size = cols*tile_size, rows*tile_size 
		self.screen = pygame.display.set_mode(size)
		self.clock = pygame.time.Clock()
		self.particles = []
		self.game_loop()

	def draw_screen(self):
		# self.screen.blit(bg, (0, 0))
		self.screen.fill(0)
		self.particles_run(random.randint(0, 500), (255, 255, 255))
		for nrow, row in enumerate(grid.lyt_surfaces):
			for ncol, col in enumerate(row):
				self.screen.blit(col, (ncol*64, nrow*64))

	def particles_run(self, pos, color):
	    """ Creates particles starting from pos with a color """
	    self.particles.append([
	        [pos, 0],
	        [random.randint(0, 20) / 10 - 1, 2],
	        random.randint(4,6)])
	    # Moving the coordinates and size of self.particles
	    for particle in self.particles[:]:
	        particle[0][0] += particle[1][0]
	        particle[0][1] += particle[1][1]
	        particle[2] -= 0.005 # how fast circles shrinks
	        particle[1][1] += 0.01 # circles speed
	        # if particle[2] <= 0:
	        if particle[0][1] > 512:
	            self.particles.remove(particle)
	    # Draw circles
	    for particle in self.particles:
	        pygame.draw.circle(
	            self.screen, (color),
	        (round(particle[0][0]), round(particle[0][1])),
	         round(particle[2]))
	
	def game_loop(self):
		loop = 1
		count_taken = 0
		score = 0
		while loop:
			if score == 32:
				print("YOU WIN!")
				winsound.Beep(150, 200)
				winsound.Beep(1500, 200)
				winsound.Beep(150, 200)
				winsound.Beep(1500, 200)
				winsound.Beep(1500, 200)
				winsound.Beep(1500, 200)
				# pygame.mixer.Sound.play(self.snd_win)
				# pygame.mixer.Sound.play(self.snd_win)
				# pygame.mixer.Sound.play(self.snd_win)
				loop = 0
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					loop = 0
				if event.type == pygame.MOUSEBUTTONDOWN:
					x, y = pygame.mouse.get_pos()
					col, row = x//64,  y//64

					if grid.lyt[row][col] != [0,0,0]:
						# pygame.mixer.Sound.play(self.snd_click)
						print(grid.lyt[row][col])
						count_taken += 1
						print(f"{count_taken=}")
						if count_taken == 1 :
							winsound.Beep(200, 100)
							first = grid.lyt[row][col]
							r1, c1 = row, col
						elif count_taken == 2:
							second = grid.lyt[row][col]
							r2, c2 = row, col
							if (r2, c2) != (r1, c1):
								print(r2, c2, "-", r1, c1)
								if first == second:
									print("Hai trovato una coppia")
									score += 1
									# pygame.mixer.Sound.play(self.snd_win)
									winsound.Beep(1500, 100)
									count_taken = 0
									grid.lyt_surfaces[r1][c1].fill((0,0,0,0))
									grid.lyt_surfaces[r1][c1].set_colorkey((0,0,0))
									grid.lyt[r1][c1] = [0,0,0]
									grid.lyt_surfaces[r2][c2].fill((0,0,0,0))
									grid.lyt_surfaces[r2][c2].set_colorkey((0,0,0))
									grid.lyt[r2][c2] = [0,0,0]
									grid.set_surfaces()
								else:
									print("Sono diversi")
									count_taken = 0
									# pygame.mixer.Sound.play(self.snd_whip)
									# winsound.Beep(400, 100)
									winsound.Beep(150, 200)
									# winsound.PlaySound("err.wav", winsound.SND_ALIAS | winsound.SND_ASYNC)
							else:
								print("Devi cliccare su un'altra casella")
								# pygame.mixer.Sound.play(self.snd_whip)
								winsound.Beep(200, 400)
								count_taken = 0


					print(row, col)
			self.draw_screen()
			
			self.clock.tick(60)
			pygame.display.flip()
		pygame.quit()




grid = Generator()
# print(grid.lyt_surfaces)
Win()

And we havent used any image or sound that is not generated by the script itself.

Repository of the game Matchpair

https://github.com/formazione/matchpair

Hiding the tiles this time

A match pair game that shows the tiles can be made on purpose, but maybe you want them to be hidden, so…

import random
import pygame
import winsound
from time import sleep


frequency = 2500  # Set Frequency To 2500 Hertz
duration = 100  # Set Duration To 1000 ms == 1 second

tile_size = 84

class Generator:
	def __init__(self):
		self.lyt = [
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,],
			[0,0,0,0,0,0,0,0,]
		]

		ncells = len(self.lyt)*len(self.lyt[0])
		print(f"{ncells=}")
		clrs = []
		self.populate_color()
		# print(self.lyt)
		# print(self.lyt_surfaces)

	def clr(self):
		return random.randrange(50, 255, 10)
	
	def populate_color(self):
		''' creates 32 random color + 32 like the first 32 '''
		for r, line in enumerate(self.lyt):
			for c, x in enumerate(line):
				color = [self.clr(), self.clr(), self.clr()]
				self.lyt[r][c] = color
				# surf = pygame.Surface((tile_size,tile_size))
				# surf.fill(color)
				# self.lyt_surfaces.append(surf)
		self.lyt[:4] = self.lyt[4:9]
		self.shuffle_colors()
		self.set_surfaces()

	def shuffle_colors(self):
		for n, line in enumerate(self.lyt):
			self.lyt[n] = random.sample(line, len(line))
		random.shuffle(self.lyt)
		print(*self.lyt, sep="\n")

	def set_surfaces(self):
		self.lyt_surfaces = [] # contains surfaces
		self.drk_surfaces = [] # contains surfaces
		for r, line in enumerate(self.lyt):
			row_clr = []
			row_drk = []
			for c, color in enumerate(line):
				surf = pygame.Surface((tile_size,tile_size))
				surf.fill(color)
				row_clr.append(surf)
				drk = pygame.Surface((tile_size, tile_size))
				drk.fill((0,0,0))
				row_drk.append(drk)
			self.lyt_surfaces.append(row_clr)
			self.drk_surfaces.append(row_drk)
		# print(self.lyt_surfaces)
		


first_try = 0
couple = 0
class Win:
	def __init__(self):
		pygame.init()
		couples = 32
		cols, rows = (8,8)
		# tile_size = tile_size
		size = cols*tile_size, rows*tile_size 
		self.screen = pygame.display.set_mode(size)
		self.clock = pygame.time.Clock()
		self.particles = []
		self.game_loop()

	def draw_screen(self):
		# self.screen.blit(bg, (0, 0))
		self.screen.fill(0)
		self.particles_run(random.randint(0, 500), (255, 255, 255))
		for nrow, row in enumerate(grid.drk_surfaces):
			for ncol, col in enumerate(row):
				self.screen.blit(col, (ncol*tile_size, nrow*tile_size))
		for x in range(8):
			pygame.draw.line(self.screen, (255, 255, 255), (tile_size*x, 0), (tile_size*x, 8 * tile_size))
			pygame.draw.line(self.screen, (255, 255, 255), (0, tile_size * x), (8 * tile_size, tile_size * x))
		pygame.draw.line(self.screen, (255, 255, 255), (tile_size * 8 - 1, 0), (tile_size * 8- 1, 8 * tile_size))
		pygame.draw.line(self.screen, (255, 255, 255), (0, tile_size * 8 - 1), (8 * tile_size, tile_size * 8 - 1))

	def particles_run(self, pos, color):
	    """ Creates particles starting from pos with a color """
	    self.particles.append([
	        [pos, 0],
	        [random.randint(0, 20) / 10 - 1, 2],
	        random.randint(4,6)])
	    # Moving the coordinates and size of self.particles
	    for particle in self.particles[:]:
	        particle[0][0] += particle[1][0]
	        particle[0][1] += particle[1][1]
	        particle[2] -= 0.005 # how fast circles shrinks
	        particle[1][1] += 0.01 # circles speed
	        # if particle[2] <= 0:
	        if particle[0][1] > 512:
	            self.particles.remove(particle)
	    # Draw circles
	    for particle in self.particles:
	        pygame.draw.circle(
	            self.screen, (color),
	        (round(particle[0][0]), round(particle[0][1])),
	         round(particle[2]))
	def delete(self, r1, c1, r2, c2):
		srf_black = pygame.Surface((tile_size, tile_size))
		srf_black.fill((0,0,0))
		grid.drk_surfaces[r1][c1] = srf_black
		srf_black = pygame.Surface((tile_size, tile_size))
		srf_black.fill((0,0,0))
		grid.drk_surfaces[r2][c2] = srf_black
	def game_loop(self):
		global first_try

		loop = 1
		count_taken = 0
		score = 0
		while loop:
			if score == 32:
				print("YOU WIN!")
				winsound.Beep(150, 200)
				winsound.Beep(1500, 200)
				winsound.Beep(150, 200)
				winsound.Beep(1500, 200)
				winsound.Beep(1500, 200)
				winsound.Beep(1500, 200)
				loop = 0
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					loop = 0
				if event.type == pygame.MOUSEBUTTONDOWN:
					x, y = pygame.mouse.get_pos()
					col, row = x//tile_size,  y//tile_size

					if grid.lyt[row][col] != [0,0,0]:
						print(grid.lyt[row][col])
						count_taken += 1
						print(f"{count_taken=}")
						# ===================================== [ 1 ] === #
						if count_taken == 1 :
							try:
								if couple == 0:
									self.delete(r1, c1, r2, c2)
							except:
								pass
							winsound.Beep(200, 100)
							first = grid.lyt[row][col]
							r1, c1 = row, col
							surf1 = grid.lyt_surfaces[r1][c1].copy()
							grid.drk_surfaces[r1][c1] = surf1
						# ===================================== [ 2 ] === #
						if count_taken == 2:
							winsound.Beep(200, 100)
							second = grid.lyt[row][col]
							r2, c2 = row, col
							surf2 = grid.lyt_surfaces[r2][c2].copy()
							grid.drk_surfaces[r2][c2] = surf2

							if (r2, c2) != (r1, c1):
								print(r2, c2, "-", r1, c1)
								if first == second:
									print("Hai trovato una coppia")
									score += 1
									winsound.Beep(1500, 100)
									count_taken = 0
									grid.lyt[r1][c1] = [0,0,0]
									grid.lyt[r2][c2] = [0,0,0]
									couple = 1
								else:
									print("Sono diversi")
									count_taken = 0
									grid.lyt_surfaces[r1][c1] = surf1.copy()
									grid.lyt_surfaces[r2][c2] = surf2.copy()
									couple = 0

									
							else:
								print("Devi cliccare su un'altra casella")
								# pygame.mixer.Sound.play(self.snd_whip)
								winsound.Beep(200, 400)
								grid.lyt_surfaces[r1][c1] = surf1.copy()
								count_taken = 0


					print(row, col)
			self.draw_screen()
			
			self.clock.tick(60)
			pygame.display.flip()
		pygame.quit()




grid = Generator()
# print(grid.lyt_surfaces)
Win()
This time you cannot see all the tiles, but just the ones you click on to

Subscribe to the newsletter for updates
Tkinter templates
Avatar My youtube channel

Twitter: @pythonprogrammi - python_pygame

Videos

Speech recognition game

Pygame's Platform Game

Other Pygame's posts

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.