暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
大家運行程序後,會首先彈出選擇框,是否從第一關開始,選擇第一關後,點擊遊戲便可以開始遊戲。我們設計了一個菜單,點擊遊戲/開始遊戲即可!
02.
把火影忍者的人物放畫布
接下來就是將遊戲人物放到畫布上去,這裡我們選擇了我最喜歡的火影忍者的頭像,哈哈!
1).首先程序規定了每一個種類圖片
圖片所能出現的次數為4次,然後如果我們想實現一個8x8大小的圖片地圖,那麼就一共有8x8/4=16種類型的圖片可以出現。我們將每一種類型圖片編碼為一個數字,例如上圖中鳴人的編號為0,小櫻的編號為1。然後在對應到圖片上去,所以就會得到16(種類)x4(每個種類的圖片數量)=64個圖片,如下圖所示:
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
大家運行程序後,會首先彈出選擇框,是否從第一關開始,選擇第一關後,點擊遊戲便可以開始遊戲。我們設計了一個菜單,點擊遊戲/開始遊戲即可!
02.
把火影忍者的人物放畫布
接下來就是將遊戲人物放到畫布上去,這裡我們選擇了我最喜歡的火影忍者的頭像,哈哈!
1).首先程序規定了每一個種類圖片
圖片所能出現的次數為4次,然後如果我們想實現一個8x8大小的圖片地圖,那麼就一共有8x8/4=16種類型的圖片可以出現。我們將每一種類型圖片編碼為一個數字,例如上圖中鳴人的編號為0,小櫻的編號為1。然後在對應到圖片上去,所以就會得到16(種類)x4(每個種類的圖片數量)=64個圖片,如下圖所示:
2).然後,我們將上述的圖片打亂
按照畫布上的位置分別放置圖片,就得到了連連看的圖片界面。
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
大家運行程序後,會首先彈出選擇框,是否從第一關開始,選擇第一關後,點擊遊戲便可以開始遊戲。我們設計了一個菜單,點擊遊戲/開始遊戲即可!
02.
把火影忍者的人物放畫布
接下來就是將遊戲人物放到畫布上去,這裡我們選擇了我最喜歡的火影忍者的頭像,哈哈!
1).首先程序規定了每一個種類圖片
圖片所能出現的次數為4次,然後如果我們想實現一個8x8大小的圖片地圖,那麼就一共有8x8/4=16種類型的圖片可以出現。我們將每一種類型圖片編碼為一個數字,例如上圖中鳴人的編號為0,小櫻的編號為1。然後在對應到圖片上去,所以就會得到16(種類)x4(每個種類的圖片數量)=64個圖片,如下圖所示:
2).然後,我們將上述的圖片打亂
按照畫布上的位置分別放置圖片,就得到了連連看的圖片界面。
3).部分代碼如下圖所示
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
大家運行程序後,會首先彈出選擇框,是否從第一關開始,選擇第一關後,點擊遊戲便可以開始遊戲。我們設計了一個菜單,點擊遊戲/開始遊戲即可!
02.
把火影忍者的人物放畫布
接下來就是將遊戲人物放到畫布上去,這裡我們選擇了我最喜歡的火影忍者的頭像,哈哈!
1).首先程序規定了每一個種類圖片
圖片所能出現的次數為4次,然後如果我們想實現一個8x8大小的圖片地圖,那麼就一共有8x8/4=16種類型的圖片可以出現。我們將每一種類型圖片編碼為一個數字,例如上圖中鳴人的編號為0,小櫻的編號為1。然後在對應到圖片上去,所以就會得到16(種類)x4(每個種類的圖片數量)=64個圖片,如下圖所示:
2).然後,我們將上述的圖片打亂
按照畫布上的位置分別放置圖片,就得到了連連看的圖片界面。
3).部分代碼如下圖所示
該函數是對畫布圖片進行一個初始化:
- 首先,是將每一個類別的小圖片都添加self.num張,形成一個self.picsKind * self.num大小的一維數組;
- 然後,將小圖片的索引順序進行打亂;
- 最後,是將小圖片的索引轉化為一個二維數組,也就是呈現給大家的一個正方形的界面。
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
大家運行程序後,會首先彈出選擇框,是否從第一關開始,選擇第一關後,點擊遊戲便可以開始遊戲。我們設計了一個菜單,點擊遊戲/開始遊戲即可!
02.
把火影忍者的人物放畫布
接下來就是將遊戲人物放到畫布上去,這裡我們選擇了我最喜歡的火影忍者的頭像,哈哈!
1).首先程序規定了每一個種類圖片
圖片所能出現的次數為4次,然後如果我們想實現一個8x8大小的圖片地圖,那麼就一共有8x8/4=16種類型的圖片可以出現。我們將每一種類型圖片編碼為一個數字,例如上圖中鳴人的編號為0,小櫻的編號為1。然後在對應到圖片上去,所以就會得到16(種類)x4(每個種類的圖片數量)=64個圖片,如下圖所示:
2).然後,我們將上述的圖片打亂
按照畫布上的位置分別放置圖片,就得到了連連看的圖片界面。
3).部分代碼如下圖所示
該函數是對畫布圖片進行一個初始化:
- 首先,是將每一個類別的小圖片都添加self.num張,形成一個self.picsKind * self.num大小的一維數組;
- 然後,將小圖片的索引順序進行打亂;
- 最後,是將小圖片的索引轉化為一個二維數組,也就是呈現給大家的一個正方形的界面。
這裡是將我們存放到self.pics裡面的圖片,通過函數self. get_left_top_point函數來獲得其對應的座標,並按照此座標將圖片放置到畫布的相應位置。
其中有一點應用的很是巧妙,就是利用索引來作為判斷是否是一類圖片的標誌(後面有代碼示例的),接下來就是進行圖片的消除,如下圖所示。
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
大家運行程序後,會首先彈出選擇框,是否從第一關開始,選擇第一關後,點擊遊戲便可以開始遊戲。我們設計了一個菜單,點擊遊戲/開始遊戲即可!
02.
把火影忍者的人物放畫布
接下來就是將遊戲人物放到畫布上去,這裡我們選擇了我最喜歡的火影忍者的頭像,哈哈!
1).首先程序規定了每一個種類圖片
圖片所能出現的次數為4次,然後如果我們想實現一個8x8大小的圖片地圖,那麼就一共有8x8/4=16種類型的圖片可以出現。我們將每一種類型圖片編碼為一個數字,例如上圖中鳴人的編號為0,小櫻的編號為1。然後在對應到圖片上去,所以就會得到16(種類)x4(每個種類的圖片數量)=64個圖片,如下圖所示:
2).然後,我們將上述的圖片打亂
按照畫布上的位置分別放置圖片,就得到了連連看的圖片界面。
3).部分代碼如下圖所示
該函數是對畫布圖片進行一個初始化:
- 首先,是將每一個類別的小圖片都添加self.num張,形成一個self.picsKind * self.num大小的一維數組;
- 然後,將小圖片的索引順序進行打亂;
- 最後,是將小圖片的索引轉化為一個二維數組,也就是呈現給大家的一個正方形的界面。
這裡是將我們存放到self.pics裡面的圖片,通過函數self. get_left_top_point函數來獲得其對應的座標,並按照此座標將圖片放置到畫布的相應位置。
其中有一點應用的很是巧妙,就是利用索引來作為判斷是否是一類圖片的標誌(後面有代碼示例的),接下來就是進行圖片的消除,如下圖所示。
03.
核心算法解釋
敲黑板劃重點來了,只有符合上述三種情況的圖片我們才能夠消除,那麼程序如何判斷二者是否符合被消除的條件呢?
- 我們以直線連接為例。上圖中可以直線連接的兩個佐助橫縱座標分別為(2,3)和(3,3),那麼我們就判斷他們x座標(直線連接,橫縱座標肯定有一個相等,就不用判斷相等的座標了);
- 如果他們中間沒有其他的圖片,那麼他們就可以被連接然後消掉,否則就不可以;
例如(4,4)和(4,6)的小櫻之間有一個其他人的存在,他們就不能被連接,其他的情況也是類似判斷,部分代碼如下圖所示:
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
大家運行程序後,會首先彈出選擇框,是否從第一關開始,選擇第一關後,點擊遊戲便可以開始遊戲。我們設計了一個菜單,點擊遊戲/開始遊戲即可!
02.
把火影忍者的人物放畫布
接下來就是將遊戲人物放到畫布上去,這裡我們選擇了我最喜歡的火影忍者的頭像,哈哈!
1).首先程序規定了每一個種類圖片
圖片所能出現的次數為4次,然後如果我們想實現一個8x8大小的圖片地圖,那麼就一共有8x8/4=16種類型的圖片可以出現。我們將每一種類型圖片編碼為一個數字,例如上圖中鳴人的編號為0,小櫻的編號為1。然後在對應到圖片上去,所以就會得到16(種類)x4(每個種類的圖片數量)=64個圖片,如下圖所示:
2).然後,我們將上述的圖片打亂
按照畫布上的位置分別放置圖片,就得到了連連看的圖片界面。
3).部分代碼如下圖所示
該函數是對畫布圖片進行一個初始化:
- 首先,是將每一個類別的小圖片都添加self.num張,形成一個self.picsKind * self.num大小的一維數組;
- 然後,將小圖片的索引順序進行打亂;
- 最後,是將小圖片的索引轉化為一個二維數組,也就是呈現給大家的一個正方形的界面。
這裡是將我們存放到self.pics裡面的圖片,通過函數self. get_left_top_point函數來獲得其對應的座標,並按照此座標將圖片放置到畫布的相應位置。
其中有一點應用的很是巧妙,就是利用索引來作為判斷是否是一類圖片的標誌(後面有代碼示例的),接下來就是進行圖片的消除,如下圖所示。
03.
核心算法解釋
敲黑板劃重點來了,只有符合上述三種情況的圖片我們才能夠消除,那麼程序如何判斷二者是否符合被消除的條件呢?
- 我們以直線連接為例。上圖中可以直線連接的兩個佐助橫縱座標分別為(2,3)和(3,3),那麼我們就判斷他們x座標(直線連接,橫縱座標肯定有一個相等,就不用判斷相等的座標了);
- 如果他們中間沒有其他的圖片,那麼他們就可以被連接然後消掉,否則就不可以;
例如(4,4)和(4,6)的小櫻之間有一個其他人的存在,他們就不能被連接,其他的情況也是類似判斷,部分代碼如下圖所示:
上面的3中連接方法(直連,L型連接和U型連接)。當我們判斷二者可以連接後,利用tkinter的畫布中的delete函數,便可以將圖片刪掉。部分程序如下所示:
暑假馬上就要結束了,在暑假即將走向尾聲的時候,小編特地為大家準備了一款小遊戲——連連看。希望通過這一款小遊戲為大家放鬆身心,迎接新學年的到來。
連連看想必大家都玩過,相同的圖片,可以連在一起消掉,但前提是圖片連接的路徑要是直線,或者是“L”形(連接線有一個拐彎)或者是類似於“U”形(連接線有兩個拐彎)。那麼程序是如何實現的呢,先看一下整個的設計思路:
01.
遊戲的界面設計
1).首先是對於整體界面的設計,如下圖所示:
大家運行程序後,會首先彈出選擇框,是否從第一關開始,選擇第一關後,點擊遊戲便可以開始遊戲。我們設計了一個菜單,點擊遊戲/開始遊戲即可!
02.
把火影忍者的人物放畫布
接下來就是將遊戲人物放到畫布上去,這裡我們選擇了我最喜歡的火影忍者的頭像,哈哈!
1).首先程序規定了每一個種類圖片
圖片所能出現的次數為4次,然後如果我們想實現一個8x8大小的圖片地圖,那麼就一共有8x8/4=16種類型的圖片可以出現。我們將每一種類型圖片編碼為一個數字,例如上圖中鳴人的編號為0,小櫻的編號為1。然後在對應到圖片上去,所以就會得到16(種類)x4(每個種類的圖片數量)=64個圖片,如下圖所示:
2).然後,我們將上述的圖片打亂
按照畫布上的位置分別放置圖片,就得到了連連看的圖片界面。
3).部分代碼如下圖所示
該函數是對畫布圖片進行一個初始化:
- 首先,是將每一個類別的小圖片都添加self.num張,形成一個self.picsKind * self.num大小的一維數組;
- 然後,將小圖片的索引順序進行打亂;
- 最後,是將小圖片的索引轉化為一個二維數組,也就是呈現給大家的一個正方形的界面。
這裡是將我們存放到self.pics裡面的圖片,通過函數self. get_left_top_point函數來獲得其對應的座標,並按照此座標將圖片放置到畫布的相應位置。
其中有一點應用的很是巧妙,就是利用索引來作為判斷是否是一類圖片的標誌(後面有代碼示例的),接下來就是進行圖片的消除,如下圖所示。
03.
核心算法解釋
敲黑板劃重點來了,只有符合上述三種情況的圖片我們才能夠消除,那麼程序如何判斷二者是否符合被消除的條件呢?
- 我們以直線連接為例。上圖中可以直線連接的兩個佐助橫縱座標分別為(2,3)和(3,3),那麼我們就判斷他們x座標(直線連接,橫縱座標肯定有一個相等,就不用判斷相等的座標了);
- 如果他們中間沒有其他的圖片,那麼他們就可以被連接然後消掉,否則就不可以;
例如(4,4)和(4,6)的小櫻之間有一個其他人的存在,他們就不能被連接,其他的情況也是類似判斷,部分代碼如下圖所示:
上面的3中連接方法(直連,L型連接和U型連接)。當我們判斷二者可以連接後,利用tkinter的畫布中的delete函數,便可以將圖片刪掉。部分程序如下所示:
當我們將所有的圖片都消掉後,程序便會彈出提示框,祝賀我們闖關成功。下面,小編就為大家帶來視頻展示,看看小編的功力如何。
(連連看運行視頻)
怎麼樣看完視頻,是不是感覺還不錯,唯一美中不足的就是沒有加入聲音。大家如果有興趣的可以拿著完整的源碼改改,看看能否優化和加入聲音,這樣效果更佳!
連連看源碼:
import random, sys
import tkinter as tk
import tkinter.messagebox
from tkinter.messagebox import askyesno
from PIL import Image, ImageTk
class MainWindow():
def __init__(self):
self.title = "連連看遊戲"
self.windowWidth = 700
self.windowWidth = 700
self.windowHeigth = 500
self.root = tk.Tk()
self.root.title(self.title)
self.CWindow(self.windowWidth, self.windowHeigth)
self.root.minsize(460, 460)
self.pics = []
self.primary = askyesno(title='選擇第一關', message='第一關(yes) 第二關(no)')
self.Interface()
if self.primary == False:
self.picsize = 10 # 每行每列的圖片數量
self.num = 4
self.picWidth = 40 # 小圖片的寬
self.picHeight = 40 # 小圖片的寬
else:
self.picsize = 8 # 每行每列的圖片數量
self.num = 4
self.picWidth = 50 # 小圖片的寬
self.picHeight = 50 # 小圖片的寬
self.picsKind = self.picsize * self.picsize / self.num # 小圖片種類數量
self.picsmap = [] # 遊戲地圖
self.margin = 25
self.firstClick = True
self.start = False
self.lastPoint = None
self.none = -1
self.noLink = 0
self.lineLink = 1
self.L_Link = 2
self.U_link = 3
self.put_pic_in_pics()
self.root.mainloop()
def Interface(self):
self.menu = tk.Menu(self.root, bg="lightgrey", fg="black")
self.list_menu = tk.Menu(self.menu, tearoff=0, bg="lightgrey", fg="black")
self.list_menu.add_command(label="開始遊戲", command=self.game_start, accelerator="Ctrl+N")
self.list_menu.add_command(label="退出", command=self.game_stop, accelerator="Ctrl+M")
self.menu.add_cascade(label="遊戲", menu=self.list_menu)
self.root.configure(menu=self.menu)
self.canvas = tk.Canvas(self.root, bg='white', width=450, height=450)
self.canvas.pack(side=tk.TOP, pady=5)
self.canvas.bind('<Button-1>', self.clickCanvas)
def CWindow(self, w, h): # 設置屏幕的位置
swidth = self.root.winfo_screenwidth()
sheight = self.root.winfo_screenheight()
size = '%dx%d+%d+%d' % (w, h, (swidth - w) / 2, (sheight - h) / 2)
self.root.geometry(size)
def game_start(self):
self.ini_game()
self.put_pics_on_canvas()
self.start = True
def game_stop(self):
sys.exit()
def clickCanvas(self, event):
if self.start:
point = self.get_index_coord(Point(event.x, event.y)) # 返回鼠標點擊的位置到底是哪一幅圖片。例如[0,0]代表左上角第一幅
# 有效點擊座標
if point.isUserful() and not self.check_none(point):
if self.firstClick: # 如果是第一次點擊圖片,那麼就畫一個紅框
self.draw_red_rectangle(point)
self.firstClick = False
self.lastPoint = point
else:
if self.lastPoint.isEqual(point): # 如果連續點擊同一小圖片兩次的話,就將話得紅框去掉
self.firstClick = True
self.canvas.delete("rectRedOne")
else:
linkType = self.get_link_type(self.lastPoint, point)
if linkType['type'] != self.noLink:
# TODO Animation
self.delete_linked_points(self.lastPoint, point)
self.canvas.delete("rectRedOne")
self.firstClick = True
if self.check_end():
tk.messagebox.showinfo("You Win!", "Tip")
self.start = False
else:
self.lastPoint = point
self.canvas.delete("rectRedOne")
self.draw_red_rectangle(point)
# 判斷遊戲是否結束
def check_end(self):
for y in range(0, self.picsize):
for x in range(0, self.picsize):
if self.picsmap[y][x] != self.none:
return False
return True
def put_pic_in_pics(self): # 將小頭像放到pics數組裡面
ori_image = Image.open(r'./pic/img.png')
if self.primary == True: # 如果是第一關的話,需要將原始圖片擴大之後再進行剪裁。
ori_image = ori_image.resize((1250, 50), Image.NEAREST)
for i in range(0, int(self.picsKind)):
pic = ori_image.crop((self.picWidth * i, 0,
self.picWidth * i + self.picWidth - 1, self.picHeight - 1))
self.pics.append(ImageTk.PhotoImage(pic))
def ini_game(self): # 初始化地圖
self.picsmap = [] # 重置地圖
index1 = []
indexs = []
for i in range(0, int(self.picsKind)):
for j in range(0, self.num):
index1.append(i) # 向tmpRecords裡添加小圖片索引,每一個種類的圖片都添加self.num個
total = self.picsize * self.picsize # 總共的圖片數量
print('tmpRecords', index1)
for x in range(0, total):
index = random.randint(0, total - x - 1) # 打亂順序
indexs.append(index1[index]) # 向records裡添加小圖片的索引
del index1[index]
print('records', indexs)
print(len(indexs))
# 一維數組轉為二維,y為高維度
for y in range(0, self.picsize): # 將小圖片轉化為二維矩陣形式
for x in range(0, self.picsize):
if x == 0:
self.picsmap.append([])
self.picsmap[y].append(indexs[x + y * self.picsize])
def put_pics_on_canvas(self): # 根據地圖繪製圖像
self.canvas.delete("all")
for y in range(0, self.picsize):
for x in range(0, self.picsize):
point = self.get_left_top_point(Point(x, y)) # 獲取小圖片應該放在什麼位置(左上角的座標)
self.canvas.create_image((point.x, point.y),
image=self.pics[self.picsmap[y][x]], anchor='nw', tags='im%d%d' % (x, y)) # 將小圖片放入指定位置
def get_left_top_point(self, point): # 獲取對應矩形的左上角頂點座標
return Point(self.getx(point.x), self.gety(point.y))
def getx(self, x): # 更新x的位置
return x * self.picWidth + self.margin
def gety(self, y): # 更新y的位置
return y * self.picHeight + self.margin
def get_index_coord(self, point): # 獲取內部座標
x = -1
y = -1
for i in range(0, self.picsize):
x1 = self.getx(i)
x2 = self.getx(i + 1)
if point.x >= x1 and point.x < x2:
x = i
for j in range(0, self.picsize):
j1 = self.gety(j)
j2 = self.gety(j + 1)
if point.y >= j1 and point.y < j2:
y = j
return Point(x, y)
def draw_red_rectangle(self, point): # 選擇的區域變紅,point為內部座標
pointLT = self.get_left_top_point(point) # 獲取小圖片的左上角座標
pointRB = self.get_left_top_point(Point(point.x + 1, point.y + 1)) # 在小圖片的左上角座標上(x,y)分別加一
self.canvas.create_rectangle(pointLT.x, pointLT.y,
pointRB.x - 1, pointRB.y - 1, outline='red', tags="rectRedOne") # 以(x+1,y+1)為左上角座標,畫圓
def delete_linked_points(self, p1, p2): # 消除連通的兩個塊
self.picsmap[p1.y][p1.x] = self.none
self.picsmap[p2.y][p2.x] = self.none
self.canvas.delete('im%d%d' % (p1.x, p1.y))
self.canvas.delete('im%d%d' % (p2.x, p2.y))
def check_none(self, point): # 判斷圖上該點是否為空
if self.picsmap[point.y][point.x] == self.none:
return True
else:
return False
def get_link_type(self, p1, p2): # 判斷兩個點連通類型
# 首先判斷兩個方塊中圖片是否相同
if self.picsmap[p1.y][p1.x] != self.picsmap[p2.y][p2.x]: # 這裡運用的很巧妙,利用數字索引來判斷是否為同一類型圖片。如果不是,肯定無法連接
return {'type': self.noLink}
if self.line_link_type(p1, p2):
return {
'type': self.lineLink
}
res = self.L_Link_type(p1, p2)
if res:
return {
'type': self.L_Link,
'p1': res
}
res = self.U_Link_type(p1, p2)
if res:
return {
'type': self.U_link,
'p1': res['p1'],
'p2': res['p2']
}
return {
'type': self.noLink
}
def line_link_type(self, p1, p2): # 直線相連,判斷兩幅圖的前進道路上是否有圖片阻攔。
# 水平
if p1.y == p2.y:
# 大小判斷
if p2.x < p1.x:
start = p2.x
end = p1.x
else:
start = p1.x
end = p2.x
for x in range(start + 1, end):
if self.picsmap[p1.y][x] != self.none:
return False
return True
elif p1.x == p2.x:
if p1.y > p2.y:
start = p2.y
end = p1.y
else:
start = p1.y
end = p2.y
for y in range(start + 1, end):
if self.picsmap[y][p1.x] != self.none:
return False
return True
return False
def L_Link_type(self, p1, p2): # 一個拐彎相連,類似於“L”型
corner = Point(p1.x, p2.y)
if self.line_link_type(p1, corner) and self.line_link_type(corner, p2) and self.check_none(corner):
return corner
corner = Point(p2.x, p1.y)
if self.line_link_type(p1, corner) and self.line_link_type(corner, p2) and self.check_none(corner):
return corner
def U_Link_type(self, p1, p2): # # 兩個個拐彎相連,類似於“U”型
for y in range(-1, self.picsize + 1):
corner1 = Point(p1.x, y)
corner2 = Point(p2.x, y)
if y == p1.y or y == p2.y:
continue
if y == -1 or y == self.picsize:
if self.line_link_type(p1, corner1) and self.line_link_type(corner2, p2):
return {'p1': corner1, 'p2': corner2}
else:
if self.line_link_type(p1, corner1) and self.line_link_type(corner1,
corner2) and self.line_link_type(
corner2, p2) and self.check_none(corner1) and self.check_none(corner2):
return {'p1': corner1, 'p2': corner2}
# 橫向判斷
for x in range(-1, self.picsize + 1):
corner1 = Point(x, p1.y)
corner2 = Point(x, p2.y)
if x == p1.x or x == p2.x:
continue
if x == -1 or x == self.picsize:
if self.line_link_type(p1, corner1) and self.line_link_type(corner2, p2):
return {'p1': corner1, 'p2': corner2}
else:
if self.line_link_type(p1, corner1) and self.line_link_type(corner1,
corner2) and self.line_link_type(
corner2, p2) and self.check_none(corner1) and self.check_none(corner2):
return {'p1': corner1, 'p2': corner2}
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def isUserful(self): # 座標x和y都大於0
if self.x >= 0 and self.y >= 0:
return True
else:
return False
def isEqual(self, point): # 判斷兩個點是否相同
if self.x == point.x and self.y == point.y:
return True
else:
return False
def clone(self): # 克隆一份對象
return Point(self.x, self.y)
def changeTo(self, point): # 改為另一個對象
self.x = point.x
self.y = point.y
if __name__ == '__main__':
MainWindow()