“Python-OpnCV” How to Make 3×3 Puzzle Game. Just Prepare a Picture.

Python
higashi
higashi

Hi I’m higashi.

 

This page introduce how to make 3×3 puzzle game by using ‘Python-OpenCV’ as shown below.

You can play just prepare a appropriate picture.

The number depicted on picture can be deleted.

 

If you interested in this game, let’s make together.

 

Sponsored Links

Sample Code of Puzzle Game

It is suddenly, the below program is it.

#import library
import cv2
import numpy as np
import random
#specify the picture file
file_name='sample_pic.jpg'
#reading picture
img=cv2.imread(file_name,cv2.IMREAD_COLOR)
h,w=img.shape[:2]
#split number of puzzle
splitx=3
splity=3
counter=0
#list fir checking the clicked position
posx_list=[w/6,w/2,w*5/6]
posy_list=[h/6,h/2,h*5/6]
#designate a place where can move
pos0=[100,1,0,1,0,0,0,0,0]
pos1=[1,100,1,0,1,0,0,0,0]
pos2=[0,1,100,0,0,1,0,0,0]
pos3=[1,0,0,100,1,0,1,0,0]
pos4=[0,1,0,1,100,1,0,1,0]
pos5=[0,0,1,0,1,100,0,0,1]
pos6=[0,0,0,1,0,0,100,1,0]
pos7=[0,0,0,0,1,0,1,100,1]
pos8=[0,0,0,0,0,1,0,1,100]
pos_available=[pos0,pos1,pos2,pos3,pos4,pos5,pos6,pos7,pos8]

#split base img
def split_pic(img):
    h,w=img.shape[:2]
    cx,cy=0,0
    pic_list=[]
    for j in range(splitx):
        for i in range(splity):
            spic=img[cy:cy+int(h/splity),cx:cx+int(w/splitx),:]
            pic_list.append(spic)
            cy+=int(h/splity)
        cy=0
        cx+=int(w/splitx)
    pic_list=np.array(pic_list)
    return pic_list

#update after click
def pic_apdate(pic_list,pos_list):
    base_img=np.zeros((h,w,3),np.uint8)
    cx,cy=0,0
    for j in range(splitx):
        for i in range(splity):
            ppp=splitx*j+i
            if pos_list[ppp]!=100:
                base_img[cy:cy+int(h/splity),cx:cx+int(w/splitx),:]=pic_list[pos_list[ppp]]
            cy+=int(h/splity)
        cy=0
        cx+=int(w/splitx)
    return base_img

#update information after click
def pos_update(pos_index,pos_list,kkk):
    if pos_available[pos_list.index(100)][pos_index]==1:
        pos_list[pos_list.index(100)]=pos_list[pos_index]
        pos_list[pos_index]=100
        kkk+=1
    return pos_list,kkk


#main program of game
def play_pazzle(event, x, y, flags, params):
    global counter,img2,pos_list,kkk
    img2=np.copy(img)
    pic_list=split_pic(img)
    #initialize
    if event == cv2.EVENT_LBUTTONDOWN and counter==0:
        pos_list=[0,1,2,3,4,5,6,7,100]
        counter=1
        pos_index=0
        #make initial image
        kkk=0
        while kkk<100:
            pos_list,kkk=pos_update(pos_index,pos_list,kkk)
            pos_index=np.random.randint(0,splitx*splity)  
        new_pic=pic_apdate(pic_list,pos_list)
        cv2.imshow('window', new_pic)
    #moving plate
    elif event == cv2.EVENT_LBUTTONDOWN and counter==1:
        posx=np.argmin(np.abs(np.array(posx_list)-x))
        posy=np.argmin(np.abs(np.array(posy_list)-y))
        pos_index=posx*splitx+posy
        pos_list,kkk=pos_update(pos_index,pos_list,kkk)
        new_pic=pic_apdate(pic_list,pos_list)
        cv2.imshow('window', new_pic)
        if pos_list==[0,1,2,3,4,5,6,7,100]:
            cv2.putText(img2, 'Complete!!',(int(w/2)-150, int(h/2)+50),cv2.FONT_HERSHEY_SIMPLEX,fontScale=2,color=(0,0,0),thickness=6)
            cv2.imshow('window', img2)
            counter=0
        
#numbering to plate(not neccessaly)
h,w=img.shape[:2]
for j in range(splitx):
    for i in range(splity):
        num=j*splitx+i
        cv2.putText(img, str(num) ,(int(w/splitx*j) +100, int(h/splity*i) +100),cv2.FONT_HERSHEY_SIMPLEX,fontScale=1.0,color=(255,0,0),thickness=2)
cv2.imwrite('aaa.jpg',img)

cv2.imshow('window', img)
cv2.setMouseCallback('window', play_pazzle)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

higashi
higashi

It is extremely long program.

 

I think it is difficult to understand only this program.

So, I explain the content of program in the following items.

 

Sponsored Links

Commentary1 : Input Information Section

At first, I explain about the below section.

#import library
import cv2
import numpy as np
import random
#specify the picture file
file_name='sample_pic.jpg'
#reading picture
img=cv2.imread(file_name,cv2.IMREAD_COLOR)
h,w=img.shape[:2]
#split number of puzzle
splitx=3
splity=3
counter=0
#list fir checking the clicked position
posx_list=[w/6,w/2,w*5/6]
posy_list=[h/6,h/2,h*5/6]
#designate a place where can move
pos0=[100,1,0,1,0,0,0,0,0]
pos1=[1,100,1,0,1,0,0,0,0]
pos2=[0,1,100,0,0,1,0,0,0]
pos3=[1,0,0,100,1,0,1,0,0]
pos4=[0,1,0,1,100,1,0,1,0]
pos5=[0,0,1,0,1,100,0,0,1]
pos6=[0,0,0,1,0,0,100,1,0]
pos7=[0,0,0,0,1,0,1,100,1]
pos8=[0,0,0,0,0,1,0,1,100]
pos_available=[pos0,pos1,pos2,pos3,pos4,pos5,pos6,pos7,pos8]

In this part, the first half is importing the library, reading the image, and specifying the number of divisions.

 

Also, ‘posx_list’ and ‘posy_list’ is an array used checking the which plate is clicked when playing.

 

And the most important program in this part is arrays such as pos0, pos1, etc.

This array specifies which plate can be replaced to empty square.

 

For instance, the empty square is ‘0’ position, it can replace to ‘1’ or ‘3’ plate.

画像のマス目の解説

In ‘pos0=[100,1,0,1,0,0,0,0,0]’ , ‘100’ is where now, and ‘1’  means can replace and ‘0’
means cannot replace.

 

Based on this information, we will play the puzzle game.

Sponsored Links

Commentary2 : Definition of Sub Function

Next, I explain about below section.


#split base img
def split_pic(img):
    h,w=img.shape[:2]
    cx,cy=0,0
    pic_list=[]
    for j in range(splitx):
        for i in range(splity):
            spic=img[cy:cy+int(h/splity),cx:cx+int(w/splitx),:]
            pic_list.append(spic)
            cy+=int(h/splity)
        cy=0
        cx+=int(w/splitx)
    pic_list=np.array(pic_list)
    return pic_list

#update after click
def pic_apdate(pic_list,pos_list):
    base_img=np.zeros((h,w,3),np.uint8)
    cx,cy=0,0
    for j in range(splitx):
        for i in range(splity):
            ppp=splitx*j+i
            if pos_list[ppp]!=100:
                base_img[cy:cy+int(h/splity),cx:cx+int(w/splitx),:]=pic_list[pos_list[ppp]]
            cy+=int(h/splity)
        cy=0
        cx+=int(w/splitx)
    return base_img

#update information after click
def pos_update(pos_index,pos_list,kkk):
    if pos_available[pos_list.index(100)][pos_index]==1:
        pos_list[pos_list.index(100)]=pos_list[pos_index]
        pos_list[pos_index]=100
        kkk+=1
    return pos_list,kkk

 

At first, ‘split_pic’ function split the base image to designated numbers.

By putting these split images randomly, puzzle initial condition is made.

 

Next is about ‘pos_update’ function. (It is located at third.)

In this game, information of squares condition is stored in the variable ‘pos_list’ at anytime.

If an interchangeable location in the image were to be clicked, it is neccesay to exchange the parts, so the information of ‘pos_list’ is also updated.

 

Exchangeability is determined using the variable ‘pos_available’ mentioned above.

 

Finally, about ‘pic_update’ function.

This function update the puzzle images based on the ‘pos_list’ updated by ‘pos_update’ function.

 

Sponsored Links

Commentary3 : Definition of Main Function

Finally, below section is main program of this puzzle game.


#main program of game
def play_pazzle(event, x, y, flags, params):
    global counter,img2,pos_list,kkk
    img2=np.copy(img)
    pic_list=split_pic(img)
    #initialize
    if event == cv2.EVENT_LBUTTONDOWN and counter==0:
        pos_list=[0,1,2,3,4,5,6,7,100]
        counter=1
        pos_index=0
        #make initial image
        kkk=0
        while kkk<100:
            pos_list,kkk=pos_update(pos_index,pos_list,kkk)
            pos_index=np.random.randint(0,splitx*splity)  
        new_pic=pic_apdate(pic_list,pos_list)
        cv2.imshow('window', new_pic)
    #moving plate
    elif event == cv2.EVENT_LBUTTONDOWN and counter==1:
        posx=np.argmin(np.abs(np.array(posx_list)-x))
        posy=np.argmin(np.abs(np.array(posy_list)-y))
        pos_index=posx*splitx+posy
        pos_list,kkk=pos_update(pos_index,pos_list,kkk)
        new_pic=pic_apdate(pic_list,pos_list)
        cv2.imshow('window', new_pic)
        if pos_list==[0,1,2,3,4,5,6,7,100]:
            cv2.putText(img2, 'Complete!!',(int(w/2)-150, int(h/2)+50),cv2.FONT_HERSHEY_SIMPLEX,fontScale=2,color=(0,0,0),thickness=6)
            cv2.imshow('window', img2)
            counter=0
        
#numbering to plate(not neccessaly)
h,w=img.shape[:2]
for j in range(splitx):
    for i in range(splity):
        num=j*splitx+i
        cv2.putText(img, str(num) ,(int(w/splitx*j) +100, int(h/splity*i) +100),cv2.FONT_HERSHEY_SIMPLEX,fontScale=1.0,color=(255,0,0),thickness=2)
cv2.imwrite('aaa.jpg',img)

cv2.imshow('window', img)
cv2.setMouseCallback('window', play_pazzle)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

The processing details are as follows.

①Reading base image and click image then start game.

②By clicking second and subsequent, the game progress by using the functions that introduced above section.

③The puzzle is completed, the sentence ‘COMPLETE!!’ is displayed.

 

That is all for the commentary.

 

This time it was 3×3, but it can be applied to 4×4 and 5×5.

If you are interested, please give it a try.

 

That’s all. Thank you!!

コメント