Make a game auxiliary script with Python and share complete programming ideas

1, Explain

Description: This paper will take the 4455 Miniclip game "pet Lianliankan classic version 2" as a test case to quickly complete pairing by identifying small icons and simulating mouse clicks. It is helpful for students who are interested in learning game scripts.

Operating environment: win10 / Python 3.5.

Main modules: win32gui (identify window, window top, etc.), PIL (screenshot), numpy (create matrix), operator (compare value), pymouse (simulate mouse click).

Note:

If the installation of pymouse fails or an error is reported, you can consider installing pyHook through whl and then pyuserinput through pip.

If an error is reported [ImportError: No module named 'windows'], it can be modified__ init__.py corresponding behavior windows = > pymouse.windows.

2, Development prospect (just NAG and skip)

Game assist scripts are also popular in the current environment. For people who often play games, appropriate game assistance is still very helpful to let the computer do some tedious operations. Of course, there are other operations on higher buildings, which will not be repeated here. There are basically two kinds of game auxiliary scripts: one is to read the data of the game in memory. Ideally, you can change some basic attributes of the game. The principle is similar to many plug-ins or cracking games; Second, simulate user behavior, mouse click, keyboard operation, etc. Of course, since I have never been involved in the field of game auxiliary script, I will study it out of personal interest. The example in this paper is the second one, which mainly simulates user behavior and allows the program to replace user operation.

3, Development process

Let's look at the program diagram first:

The browser opens the game window (a single window). The game interface is shown in the figure below. The screenshot of the main interface of the game needs two coordinates (upper left corner coordinates and lower right corner coordinates). The origin is generally the upper left corner of the screen. Students who are uncertain about the coordinate point value can take a full screen screenshot and view the coordinate value with the image editing software. Get the window handle. Here is the title of the browser's title bar (right click - view source code - title, plus the software name). For example: "pets watch Classic 2, pets watch Classic 2 games, 4455 Miniclip games www.4399.com - Google Chrome". Get the window handle and you can start.

Overall development idea: capture the main picture of the game -- > divide it into small pictures -- > compare each small picture, compare the picture acquaintance, store the number in the matrix -- > calculate the matrix continuously -- > simulate clicking.

3.1. Get the window handle and put the window on the top

python can use the Win32 GUI module to call the Windows API to operate the window. It can use the FindWindow() method to obtain the handle of the window. You need to pass in two parameters, the first is the parent window handle (fill in 0 here), and the second parameter is the name of the window (label title - Google Chrome). After obtaining the handle, you can use setforeroundwindows() The setting window is in the front. Here you can pass in the report of the game window. The code is as follows:

3.2 capture game interface, split icon and picture comparison

It takes some time to verify the program. If the captured image is not good, the subsequent operation will be affected. Therefore, the main thing is to confirm the two coordinate values of the upper left corner and the lower right corner of the game, as well as the width and height of each small icon. As shown in the figure below, first intercept the whole game interface, then divide the small icons, then compare each icon, and then replace it with a number Icons are stored in the matrix (the numbering matrix here is inconsistent with the game diagram, and the principle is the same).

According to the upper left and lower right coordinates set in the initialization, use the ImageGrab.grab() method to take a screenshot and pass in a tuple. Then divide the large image, cut it into small icons and store them in the images_list array.

The small icon cut by the above code is converted into a digital matrix. If the icon has been stored in the image_type_list, this index is returned. If it does not exist, it is appended. Then the current length is the number of the newly added icon. The code is as follows:

The above getIndex is to compare the pictures to determine whether the icon has appeared (whether it already exists in the image_type_list, and if it does not appear, it will be added). Here, the Hamming distance is used to determine the acquaintance of the two pictures, and the threshold value is set to 10. When it is less than the threshold value, it is considered to be the same picture. The specific code is as follows:

4, Program core - icon connection algorithm (path finding)

Here is only a simple analysis of the algorithm code. If you don't understand the program well, you can leave a message and analyze the image and text in the follow-up.

Through the above development process, the following matrix is basically obtained. As long as two values with the same number are compared to find the connectable path, and if found, the simulated click operation is carried out. Here is a brief introduction to the rules of the game: 8 rows by 12 columns of the game icon area, and the peripheral 0 actually means that the path can be passed when looking for the path. For example, the coordinates (1,1) can be compared with (1,10) Connect, (7,1) and (7,2).

The idea of the algorithm: the first step in finding a path is to find a set of coordinates that can be directly connected horizontally and vertically. For example, the set of coordinates p1 (1,1) has [(0,1), (1,0)], and the connectable set of coordinates p2 (1,10) is [(0,10)] , then compare the connectable coordinate sets of p1 and p2. If the coordinates in the set are also connectable, it means that p1 and p2 are connectable. Obviously, (0,1) and (0,10) are the same line and connectable, which means that there are connectable paths between p1 and p2. The code is as follows: code implementation process under simple analysis: in isReachable() Pass in two coordinate values to be compared, then obtain the coordinate sets that can be connected horizontally and vertically (isRowConnect(), iscoconnect()) of two points respectively, and finally traverse the set to compare whether there is connectable. If so, it means that the two coordinates passed in can be connected.

5, Development summary

Learning such a game auxiliary script is also very helpful for individuals to cultivate their interest in programming. It is a good pastime after work. I will study and learn from these directions in the future. This case is just screenshots, comparative pictures and simulated mouse clicks. I think it can be more powerful, and it is not limited to the field of games. I believe you should You should have seen the software that automatically sends QQ messages. I think it can be done. There are many simulation operations that can be realized: mouse wheel, left and right keys, keyboard input, etc.

6, Attachment - source code

Note: the source code is for learning only

1 # -*- coding:utf-8 -*-
 2
 3 import win32gui
 4 import time
 5 from PIL import ImageGrab, Image
 6 import numpy as np
 7 import operator
 8 from pymouse import PyMouse
 9
 10
 11 class GameAssist:
 12
 13 def __init__(self, wdname):
 14 """initialization"""
 15
 16 #  Get window handle
 17 self.hwnd = win32gui.FindWindow(0, wdname)
 18 if not self.hwnd:
 19 print("The window cannot be found. Please confirm the window handle Name:[%s]" % wdname )
 20 exit()
 21
 22 #  The window is displayed at the front
 23 win32gui.SetForegroundWindow(self.hwnd)
 24
 25 #  Small icon numbering matrix
 26 self.im2num_arr = []
 27
 28 #  Upper left and lower right coordinates of the main screenshot
 29 self.scree_left_and_right_point = (299, 251, 768, 564)
 30 #  Small icon width and height
 31 self.im_width = 39
 32
 33 #  PyMouse object, mouse click
 34 self.mouse = PyMouse()
 35
 36 def screenshot(self):
 37 """Screenshot"""
 38
 39 #  1. grab function screenshot with parameters of upper left corner and lower right corner
 40 # image = ImageGrab.grab((417, 257, 885, 569))
 41 image = ImageGrab.grab(self.scree_left_and_right_point)
 42
 43 #  2. Slitting graph
 44 # exit()
 45 image_list = {}
 46 offset = self.im_width # 39
 47
 48 #  8 rows and 12 columns
 49 for x in range(8):
 50 image_list[x] = {}
 51 for y in range(12):
 52 # print("show",x, y)
 53 # exit()
 54 top = x * offset
 55 left = y * offset
 56 right = (y + 1) * offset
 57 bottom = (x + 1) * offset
 58
 59 #  Cut into small icons with the crop function. The parameters are the upper left corner and the lower right corner of the icon
 60 im = image.crop((left, top, right, bottom))
 61 #  Store the cut icon in the corresponding position
 62 image_list[x][y] = im
 63
 64 return image_list
 65
 66 def image2num(self, image_list):
 67 """Convert icon matrix to digital matrix"""
 68
 69 #  1. Create an all zero matrix and an empty one-dimensional array
 70 arr = np.zeros((10, 14), dtype=np.int32) #  Replace pictures with numbers
 71 image_type_list = []
 72
 73 #  2. Identify different pictures and convert the picture matrix into a digital matrix
 74 for i in range(len(image_list)):
 75 for j in range(len(image_list[0])):
 76 im = image_list[i][j]
 77
 78 #  Verify that the current icon has been saved
 79 index = self.getIndex(im, image_type_list)
 80
 81 #  image_type_list does not exist
 82 if index < 0:
 83 image_type_list.append(im)
 84 arr[i + 1][j + 1] = len(image_type_list)
 85 else:
 86 arr[i + 1][j + 1] = index + 1
 87
 88 print("Number of icons:", len(image_type_list))
 89
 90 self.im2num_arr = arr
 91 return arr
 92
 93 #  Check whether there are icons in the array. If so, return the index to the following table
 94 def getIndex(self,im, im_list):
 95 for i in range(len(im_list)):
 96 if self.isMatch(im, im_list[i]):
 97 return i
 98
 99 return -1
100
101 #  Hamming distance determines whether the two icons are the same
102 def isMatch(self, im1, im2):
103
104 #  Reduce the icon to grayscale
105 image1 = im1.resize((20, 20), Image.ANTIALIAS).convert("L")
106 image2 = im2.resize((20, 20), Image.ANTIALIAS).convert("L")
107
108 #  Convert the gray icon to 01 string, that is, binary data
109 pixels1 = list(image1.getdata())
110 pixels2 = list(image2.getdata())
111
112 avg1 = sum(pixels1) / len(pixels1)
113 avg2 = sum(pixels2) / len(pixels2)
114 hash1 = "".join(map(lambda p: "1" if p > avg1 else "0", pixels1))
115 hash2 = "".join(map(lambda p: "1" if p > avg2 else "0", pixels2))
116
117 #  Count the number of two 01 strings of different numbers
118 match = sum(map(operator.ne, hash1, hash2))
119
120 #  The threshold is set to 10
121 return match < 10
122
123 #  Judge whether the matrix is all 0
124 def isAllZero(self, arr):
125 for i in range(1, 9):
126 for j in range(1, 13):
127 if arr[i][j] != 0:
128 return False
129 return True
130
131 #  Are they in the same row or in the same column and can be connected
132 def isReachable(self, x1, y1, x2, y2):
133 #  1. First judge whether the values are the same
134 if self.im2num_arr[x1][y1] != self.im2num_arr[x2][y2]:
135 return False
136
137 #  1. Obtain two coordinate arrays that can be connected in the same row or column respectively
138 list1 = self.getDirectConnectList(x1, y1)
139 list2 = self.getDirectConnectList(x2, y2)
140 # print(x1, y1, list1)
141 # print(x2, y2, list2)
142
143 # exit()
144
145 #  2. Compare whether the coordinate array is connectable
146 for x1, y1 in list1:
147 for x2, y2 in list2:
148 if self.isDirectConnect(x1, y1, x2, y2):
149 return True
150 return False
151
152 #  Gets an array of coordinates that can be connected in the same row or column
153 def getDirectConnectList(self, x, y):
154
155 plist = []
156 for px in range(0, 10):
157 for py in range(0, 14):
158 #  Get the coordinates of the same row or column with 0
159 if self.im2num_arr[px][py] == 0 and self.isDirectConnect(x, y, px, py):
160 plist.append([px, py])
161
162 return plist
163
164 #  Are they in the same row or in the same column and can be connected
165 def isDirectConnect(self, x1, y1, x2, y2):
166 #  1. The position is exactly the same
167 if x1 == x2 and y1 == y2:
168 return False
169
170 #  2. The ranks are different
171 if x1 != x2 and y1 != y2:
172 return False
173
174 #  3. Peer
175 if x1 == x2 and self.isRowConnect(x1, y1, y2):
176 return True
177
178 #  4. Same column
179 if y1 == y2 and self.isColConnect(y1, x1, x2):
180 return True
181
182 return False
183
184 #  Judge whether peers can connect
185 def isRowConnect(self, x, y1, y2):
186 minY = min(y1, y2)
187 maxY = max(y1, y2)
188
189 #  Adjacent direct connectable
190 if maxY - minY == 1:
191 return True
192
193 #  Judge whether the two coordinates are all 0
194 for y0 in range(minY + 1, maxY):
195 if self.im2num_arr[x][y0] != 0:
196 return False
197 return True
198
199 #  Judge whether the same column can be connected
200 def isColConnect(self, y, x1, x2):
201 minX = min(x1, x2)
202 maxX = max(x1, x2)
203
204 #  Adjacent direct connectable
205 if maxX - minX == 1:
206 return True
207
208 #  Judge whether the two coordinates are all 0
209 for x0 in range(minX + 1, maxX):
210 if self.im2num_arr[x0][y] != 0:
211 return False
212 return True
213
214 #  Click the event and set the array to 0
215 def clickAndSetZero(self, x1, y1, x2, y2):
216 # print("click", x1, y1, x2, y2)
217
218 # (299, 251, 768, 564)
219 #  Principle: the middle point of the icon in the upper left corner  +  Offset
220 p1_x = int(self.scree_left_and_right_point[0] + (y1 - 1)*self.im_width + (self.im_width / 2))
221 p1_y = int(self.scree_left_and_right_point[1] + (x1 - 1)*self.im_width + (self.im_width / 2))
222
223 p2_x = int(self.scree_left_and_right_point[0] + (y2 - 1)*self.im_width + (self.im_width / 2))
224 p2_y = int(self.scree_left_and_right_point[1] + (x2 - 1)*self.im_width + (self.im_width / 2))
225
226 time.sleep(0.2)
227 self.mouse.click(p1_x, p1_y)
228 time.sleep(0.2)
229 self.mouse.click(p2_x, p2_y)
230
231 #  Set the matrix value to 0
232 self.im2num_arr[x1][y1] = 0
233 self.im2num_arr[x2][y2] = 0
234
235 print("Elimination:(%d, %d) (%d, %d)" % (x1, y1, x2, y2))
236 # exit()
237
238 #  Program entrance, control center
239 def start(self):
240
241 #  1. First intercept the big picture of the game area, and then cut each small picture
242 image_list = self.screenshot()
243
244 #  2. Identify small icons and collect numbers
245 self.image2num(image_list)
246
247 print(self.im2num_arr)
248
249 #  3. Traverse to find the coordinates that can be connected
250 while not self.isAllZero(self.im2num_arr):
251 for x1 in range(1, 9):
252 for y1 in range(1, 13):
253 if self.im2num_arr[x1][y1] == 0:
254 continue
255
256 for x2 in range(1, 9):
257 for y2 in range(1, 13):
258 #  Skip to 0   Or the same
259 if self.im2num_arr[x2][y2] == 0 or (x1 == x2 and y1 == y2):
260 continue
261 if self.isReachable(x1, y1, x2, y2):
262 self.clickAndSetZero(x1, y1, x2, y2)
263
264
265 if __name__ == "__main__":
266 #  wdname   The name of the window must be written completely for continuous viewing
267 wdname = u'Pet watch classic version 2,Pet watch classic version 2 games,4399 Games www.4399.com - Google Chrome'
268
269 demo = GameAssist(wdname)
270 demo.start()
GameAssist.py

For the above content shared with you, if you need to learn resource tutorials, source code notes or want to learn and communicate, scan the code and add me to pull you into the group

Tags: Python crawler Game Development script

Posted on Sun, 28 Nov 2021 08:07:35 -0500 by bigmichael