這篇文章主要介紹了如何基于Python實現自動掃雷,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
自動掃雷一般分為兩種,一種是讀取內存數據,而另一種是通過分析圖片獲得數據,并通過模擬鼠標操作,這里我用的是第二種方式。
一、準備工作
我的版本是 python 3.6.1
python的第三方庫:
- win32api
- win32gui
- win32con
- Pillow
- numpy
- opencv
可通過 pip install --upgrade SomePackage 來進行安裝
注意:有的版本是下載pywin32,但是有的要把pywin32升級到最高并自動下載了pypiwin32,具體情況每個python版本可能都略有不同
我給出我的第三方庫和版本僅供參考
二、關鍵代碼組成
1.找到游戲窗口與坐標
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#掃雷游戲窗口 class_name = "TMain" title_name = "Minesweeper Arbiter " hwnd = win32gui.FindWindow(class_name, title_name) #窗口坐標 left = 0 top = 0 right = 0 bottom = 0 if hwnd: print ( "找到窗口" ) left, top, right, bottom = win32gui.GetWindowRect(hwnd) #win32gui.SetForegroundWindow(hwnd) print ( "窗口坐標:" ) print ( str (left) + ' ' + str (right) + ' ' + str (top) + ' ' + str (bottom)) else : print ( "未找到窗口" ) |
2.鎖定并抓取雷區圖像
1
2
3
4
5
6
7
8
9
10
11
|
#鎖定雷區坐標 #去除周圍功能按鈕以及多余的界面 #具體的像素值是通過QQ的截圖來判斷的 left + = 15 top + = 101 right - = 15 bottom - = 42 #抓取雷區圖像 rect = (left, top, right, bottom) img = ImageGrab.grab().crop(rect) |
3.各圖像的RGBA值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#數字1-8 周圍雷數 #0 未被打開 #ed 被打開 空白 #hongqi 紅旗 #boom 普通雷 #boom_red 踩中的雷 rgba_ed = [( 225 , ( 192 , 192 , 192 )), ( 31 , ( 128 , 128 , 128 ))] rgba_hongqi = [( 54 , ( 255 , 255 , 255 )), ( 17 , ( 255 , 0 , 0 )), ( 109 , ( 192 , 192 , 192 )), ( 54 , ( 128 , 128 , 128 )), ( 22 , ( 0 , 0 , 0 ))] rgba_0 = [( 54 , ( 255 , 255 , 255 )), ( 148 , ( 192 , 192 , 192 )), ( 54 , ( 128 , 128 , 128 ))] rgba_1 = [( 185 , ( 192 , 192 , 192 )), ( 31 , ( 128 , 128 , 128 )), ( 40 , ( 0 , 0 , 255 ))] rgba_2 = [( 160 , ( 192 , 192 , 192 )), ( 31 , ( 128 , 128 , 128 )), ( 65 , ( 0 , 128 , 0 ))] rgba_3 = [( 62 , ( 255 , 0 , 0 )), ( 163 , ( 192 , 192 , 192 )), ( 31 , ( 128 , 128 , 128 ))] rgba_4 = [( 169 , ( 192 , 192 , 192 )), ( 31 , ( 128 , 128 , 128 )), ( 56 , ( 0 , 0 , 128 ))] rgba_5 = [( 70 , ( 128 , 0 , 0 )), ( 155 , ( 192 , 192 , 192 )), ( 31 , ( 128 , 128 , 128 ))] rgba_6 = [( 153 , ( 192 , 192 , 192 )), ( 31 , ( 128 , 128 , 128 )), ( 72 , ( 0 , 128 , 128 ))] rgba_8 = [( 149 , ( 192 , 192 , 192 )), ( 107 , ( 128 , 128 , 128 ))] rgba_boom = [( 4 , ( 255 , 255 , 255 )), ( 144 , ( 192 , 192 , 192 )), ( 31 , ( 128 , 128 , 128 )), ( 77 , ( 0 , 0 , 0 ))] rgba_boom_red = [( 4 , ( 255 , 255 , 255 )), ( 144 , ( 255 , 0 , 0 )), ( 31 , ( 128 , 128 , 128 )), ( 77 , ( 0 , 0 , 0 ))] |
4.掃描雷區圖像保存至一個二維數組map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#掃描雷區圖像 def showmap(): img = ImageGrab.grab().crop(rect) for y in range (blocks_y): for x in range (blocks_x): this_image = img.crop((x * block_width, y * block_height, (x + 1 ) * block_width, (y + 1 ) * block_height)) if this_image.getcolors() = = rgba_0: map [y][x] = 0 elif this_image.getcolors() = = rgba_1: map [y][x] = 1 elif this_image.getcolors() = = rgba_2: map [y][x] = 2 elif this_image.getcolors() = = rgba_3: map [y][x] = 3 elif this_image.getcolors() = = rgba_4: map [y][x] = 4 elif this_image.getcolors() = = rgba_5: map [y][x] = 5 elif this_image.getcolors() = = rgba_6: map [y][x] = 6 elif this_image.getcolors() = = rgba_8: map [y][x] = 8 elif this_image.getcolors() = = rgba_ed: map [y][x] = - 1 elif this_image.getcolors() = = rgba_hongqi: map [y][x] = - 4 elif this_image.getcolors() = = rgba_boom or this_image.getcolors() = = rgba_boom_red: global gameover gameover = 1 break #sys.exit(0) else : print ( "無法識別圖像" ) print ( "坐標" ) print ((y,x)) print ( "顏色" ) print (this_image.getcolors()) sys.exit( 0 ) #print(map) |
5.掃雷算法
這里我采用的最基礎的算法
1.首先點出一個點
2.掃描所有數字,如果周圍空白+插旗==數字,則空白均有雷,右鍵點擊空白插旗
3.掃描所有數字,如果周圍插旗==數字,則空白均沒有雷,左鍵點擊空白
4.循環2、3,如果沒有符合條件的,則隨機點擊一個白塊
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
#插旗 def banner(): showmap() for y in range (blocks_y): for x in range (blocks_x): if 1 < = map [y][x] and map [y][x] < = 5 : boom_number = map [y][x] block_white = 0 block_qi = 0 for yy in range (y - 1 ,y + 2 ): for xx in range (x - 1 ,x + 2 ): if 0 < = yy and 0 < = xx and yy < blocks_y and xx < blocks_x: if not (yy = = y and xx = = x): if map [yy][xx] = = 0 : block_white + = 1 elif map [yy][xx] = = - 4 : block_qi + = 1if boom_number = = block_white + block_qi: for yy in range (y - 1 , y + 2 ): for xx in range (x - 1 , x + 2 ): if 0 < = yy and 0 < = xx and yy < blocks_y and xx < blocks_x: if not (yy = = y and xx = = x): if map [yy][xx] = = 0 : win32api.SetCursorPos([left + xx * block_width, top + yy * block_height]) win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN, 0 , 0 , 0 , 0 ) win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP, 0 , 0 , 0 , 0 ) showmap() #點擊白塊 def dig(): showmap() iscluck = 0 for y in range (blocks_y): for x in range (blocks_x): if 1 < = map [y][x] and map [y][x] < = 5 : boom_number = map [y][x] block_white = 0 block_qi = 0 for yy in range (y - 1 , y + 2 ): for xx in range (x - 1 , x + 2 ): if 0 < = yy and 0 < = xx and yy < blocks_y and xx < blocks_x: if not (yy = = y and xx = = x): if map [yy][xx] = = 0 : block_white + = 1 elif map [yy][xx] = = - 4 : block_qi + = 1if boom_number = = block_qi and block_white > 0 : for yy in range (y - 1 , y + 2 ): for xx in range (x - 1 , x + 2 ): if 0 < = yy and 0 < = xx and yy < blocks_y and xx < blocks_x: if not (yy = = y and xx = = x): if map [yy][xx] = = 0 : win32api.SetCursorPos([left + xx * block_width, top + yy * block_height]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0 , 0 , 0 , 0 ) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0 , 0 , 0 , 0 ) iscluck = 1 if iscluck = = 0 : luck() #隨機點擊 def luck(): fl = 1 while (fl): random_x = random.randint( 0 , blocks_x - 1 ) random_y = random.randint( 0 , blocks_y - 1 ) if ( map [random_y][random_x] = = 0 ): win32api.SetCursorPos([left + random_x * block_width, top + random_y * block_height]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0 , 0 , 0 , 0 ) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0 , 0 , 0 , 0 ) fl = 0 def gogo(): win32api.SetCursorPos([left, top]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0 , 0 , 0 , 0 ) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0 , 0 , 0 , 0 ) showmap() global gameover while ( 1 ): if (gameover = = 0 ): banner() banner() dig() else : gameover = 0 win32api.keybd_event( 113 , 0 , 0 , 0 ) win32api.SetCursorPos([left, top]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0 , 0 , 0 , 0 ) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0 , 0 , 0 , 0 ) showmap() |
這個算法在初級和中級通過率都不錯,但是在高級成功率慘不忍睹,主要是沒有考慮邏輯組合以及白塊是雷的概率問題,可以對這兩個點進行改進,提高成功率。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://www.cnblogs.com/chengxyuan/p/12146977.html