python连连看源代码,会玩连连看脚本

  python连连看源代码,会玩连连看脚本

  最近女朋友在玩连连看,玩了一个星期了,还没清。真的是一道菜。我受不了了。我直接用python写了一个脚本代码,可以自动播放连连看。有兴趣的可以去了解一下。

  00-1010对实施步骤的所有代码排序

  

目录

  最近女朋友在玩连连看,玩了一个星期了,还没清。真的是一道菜。

  我实在受不了了,就直接用python写了个脚本代码,一分钟一局。

  就是快,就是在网上玩容易被骂,呵呵~

  

序言

  模块导入

  导入cv2

  将numpy作为np导入

  导入win32api

  导入win32gui

  导入win32con

  从PIL进口图片抓取

  导入时间

  随机导入

  标题用于定位游戏表单。

  WINDOW_TITLE=连连看

  时间间隔是随机生成的[最小,最大]

  时间间隔最大值=0.06

  时间间隔分钟=0.1

  游戏区域从顶点的x偏移

  MARGIN_LEFT=10

  游戏区域从顶点的y偏移

  边距_高度=180

  水平正方形的数量

  h数量=19

  垂直正方形的数量

  数量=11

  正方形宽度

  点宽度=31

  方形高度

  点高度=35

  空图像编号

  EMPTY_ID=0

  切片时的左上和右下坐标:

  SUB_LT_X=8

  SUB_LT_Y=8

  SUB_RB_X=27

  SUB_RB_Y=27

  游戏的最大淘汰次数

  MAX_ROUND=200

  获取表单坐标位置。

  def getGameWindow():

  # findwindow (lpclassname=none,lpwindowname=none)窗口类名窗口标题名

  window=win32gui。FindWindow(无,WINDOW_TITLE)

  #不导航到游戏表单

  而不是window:

  打印(找不到游戏窗口,10秒后重新定位游戏窗口.)

  时间.睡眠(10)

  window=win32gui。FindWindow(无,WINDOW_TITLE)

  #导航到游戏表单

  #顶级游戏窗口

  win32gui。SetForegroundWindow(窗口)

  pos=win32gui。GetWindowRect(窗口)

  打印(“str(pos)上的游戏窗口”)

  返回(位置[0],位置[1])

  获取截图。

  def getScreenImage():

  打印(截图.)

  #获取截图图像类型对象

  scim=ImageGrab.grab()

  scim.save(screen.png )

  #用opencv阅读截图

  #获取ndarray

  返回cv2.imread(screen.png )

  区分图片和截图,处理成图。

  def getAllSquare(

  screen_image, game_pos):

      print(Processing pictures...)

      # 通过游戏窗体定位

      # 加上偏移量获取游戏区域

      game_x = game_pos[0] + MARGIN_LEFT

      game_y = game_pos[1] + MARGIN_HEIGHT

      # 从游戏区域左上开始

      # 把图像按照具体大小切割成相同的小块

      # 切割标准是按照小块的横纵坐标

      all_square = []

      for x in range(0, H_NUM):

          for y in range(0, V_NUM):

              # ndarray的切片方法 : [纵坐标起始位置:纵坐标结束为止,横坐标起始位置:横坐标结束位置]

              square = screen_image[game_y + y * POINT_HEIGHT:game_y + (y + 1) * POINT_HEIGHT,

                       game_x + x * POINT_WIDTH:game_x + (x + 1) * POINT_WIDTH]

              all_square.append(square)

      # 因为有些图片的边缘会造成干扰,所以统一把图片往内缩小一圈

      # 对所有的方块进行处理 ,去掉边缘一圈后返回

      finalresult = []

      for square in all_square:

          s = square[SUB_LT_Y:SUB_RB_Y, SUB_LT_X:SUB_RB_X]

          finalresult.append(s)

      return finalresult

  判断列表中是否存在相同图形

  存在返回进行判断图片所在的id

  否则返回-1

  

def isImageExist(img, img_list):

   i = 0

   for existed_img in img_list:

   # 两个图片进行比较 返回的是两个图片的标准差

   b = np.subtract(existed_img, img)

   # 若标准差全为0 即两张图片没有区别

   if not np.any(b):

   return i

   i = i + 1

   return -1

  

  获取所有的方块类型

  

def getAllSquareTypes(all_square):

   print("Init pictures types...")

   types = []

   # number列表用来记录每个id的出现次数

   number = []

   # 当前出现次数最多的方块

   # 这里我们默认出现最多的方块应该是空白块

   nowid = 0;

   for square in all_square:

   nid = isImageExist(square, types)

   # 如果这个图像不存在则插入列表

   if nid == -1:

   types.append(square)

   number.append(1);

   else:

   # 若这个图像存在则给计数器 + 1

   number[nid] = number[nid] + 1

   if (number[nid] > number[nowid]):

   nowid = nid

   # 更新EMPTY_ID

   # 即判断在当前这张图中的空白块id

   global EMPTY_ID

   EMPTY_ID = nowid

   print(EMPTY_ID = + str(EMPTY_ID))

   return types

  将二维图片矩阵转换为二维数字矩阵

  注意因为在上面对截屏切片时是以列为优先切片的

  所以生成的record二维矩阵每行存放的其实是游戏屏幕中每列的编号

  换个说法就是record其实是游戏屏幕中心对称后的列表

  

def getAllSquareRecord(all_square_list, types):

   print("Change map...")

   record = []

   line = []

   for square in all_square_list:

   num = 0

   for type in types:

   res = cv2.subtract(square, type)

   if not np.any(res):

   line.append(num)

   break

   num += 1

   # 每列的数量为V_NUM

   # 那么当当前的line列表中存在V_NUM个方块时我们认为本列处理完毕

   if len(line) == V_NUM:

   print(line);

   record.append(line)

   line = []

   return record

  判断给出的两个图像能否消除

  

def canConnect(x1, y1, x2, y2, r):

      result = r[:]

      # 如果两个图像中有一个为0 直接返回False

      if result[x1][y1] == EMPTY_ID or result[x2][y2] == EMPTY_ID:

          return False

      if x1 == x2 and y1 == y2:

          return False

      if result[x1][y1] != result[x2][y2]:

          return False

      # 判断横向连通

      if horizontalCheck(x1, y1, x2, y2, result):

          return True

      # 判断纵向连通

      if verticalCheck(x1, y1, x2, y2, result):

          return True

      # 判断一个拐点可连通

      if turnOnceCheck(x1, y1, x2, y2, result):

          return True

      # 判断两个拐点可连通

      if turnTwiceCheck(x1, y1, x2, y2, result):

          return True

      # 不可联通返回False

      return False

  判断横向联通

  

def horizontalCheck(x1, y1, x2, y2, result):

   if x1 == x2 and y1 == y2:

   return False

   if x1 != x2:

   return False

   startY = min(y1, y2)

   endY = max(y1, y2)

   # 判断两个方块是否相邻

   if (endY - startY) == 1:

   return True

   # 判断两个方块通路上是否都是0,有一个不是,就说明不能联通,返回false

   for i in range(startY + 1, endY):

   if result[x1][i] != EMPTY_ID:

   return False

   return True

  

  判断纵向联通

  

def verticalCheck(x1, y1, x2, y2, result):

      if x1 == x2 and y1 == y2:

          return False

      if y1 != y2:

          return False

      startX = min(x1, x2)

      endX = max(x1, x2)

      # 判断两个方块是否相邻

      if (endX - startX) == 1:

          return True

      # 判断两方块儿通路上是否可连。

      for i in range(startX + 1, endX):

          if result[i][y1] != EMPTY_ID:

              return False

      return True

  判断一个拐点可联通

  

def turnOnceCheck(x1, y1, x2, y2, result):

      if x1 == x2 or y1 == y2:

          return False

      cx = x1

      cy = y2

      dx = x2

      dy = y1

      # 拐点为空,从第一个点到拐点并且从拐点到第二个点可通,则整条路可通。

      if result[cx][cy] == EMPTY_ID:

          if horizontalCheck(x1, y1, cx, cy, result) and verticalCheck(cx, cy, x2, y2, result):

              return True

      if result[dx][dy] == EMPTY_ID:

          if verticalCheck(x1, y1, dx, dy, result) and horizontalCheck(dx, dy, x2, y2, result):

              return True

      return False

  判断两个拐点可联通

  

def turnTwiceCheck(x1, y1, x2, y2, result):

      if x1 == x2 and y1 == y2:

          return False

      # 遍历整个数组找合适的拐点

      for i in range(0, len(result)):

          for j in range(0, len(result[1])):

              # 不为空不能作为拐点

              if result[i][j] != EMPTY_ID:

                  continue

              # 不和被选方块在同一行列的不能作为拐点

              if i != x1 and i != x2 and j != y1 and j != y2:

                  continue

              # 作为交点的方块不能作为拐点

              if (i == x1 and j == y2) or (i == x2 and j == y1):

                  continue

              if turnOnceCheck(x1, y1, i, j, result) and (

                      horizontalCheck(i, j, x2, y2, result) or verticalCheck(i, j, x2, y2, result)):

                  return True

              if turnOnceCheck(i, j, x2, y2, result) and (

                      horizontalCheck(x1, y1, i, j, result) or verticalCheck(x1, y1, i, j, result)):

                  return True

      return False

  自动消除

  

def autoRelease(result, game_x, game_y):

      # 遍历地图

      for i in range(0, len(result)):

          for j in range(0, len(result[0])):

              # 当前位置非空

              if result[i][j] != EMPTY_ID:

                  # 再次遍历地图 寻找另一个满足条件的图片

                  for m in range(0, len(result)):

                      for n in range(0, len(result[0])):

                          if result[m][n] != EMPTY_ID:

                              # 若可以执行消除

                              if canConnect(i, j, m, n, result):

                                  # 消除的两个位置设置为空

                                  result[i][j] = EMPTY_ID

                                  result[m][n] = EMPTY_ID

                                  print(Remove : + str(i + 1) + , + str(j + 1) + and + str(m + 1) + , + str(

                                      n + 1))

                                  # 计算当前两个位置的图片在游戏中应该存在的位置

                                  x1 = game_x + j * POINT_WIDTH

                                  y1 = game_y + i * POINT_HEIGHT

                                  x2 = game_x + n * POINT_WIDTH

                                  y2 = game_y + m * POINT_HEIGHT

                                  # 模拟鼠标点击第一个图片所在的位置

                                  win32api.SetCursorPos((x1 + 15, y1 + 18))

                                  win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x1 + 15, y1 + 18, 0, 0)

                                  win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x1 + 15, y1 + 18, 0, 0)

                                  # 等待随机时间 ,防止检测

                                  time.sleep(random.uniform(TIME_INTERVAL_MIN, TIME_INTERVAL_MAX))

                                  # 模拟鼠标点击第二个图片所在的位置

                                  win32api.SetCursorPos((x2 + 15, y2 + 18))

                                  win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x2 + 15, y2 + 18, 0, 0)

                                  win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x2 + 15, y2 + 18, 0, 0)

                                  time.sleep(random.uniform(TIME_INTERVAL_MIN, TIME_INTERVAL_MAX))

                                  # 执行消除后返回True

                                  return True

      return False

  效果的话得上传视频,截图展现不出来效果,大家可以自行试试。

  

  

全部代码

  

# -*- coding:utf-8 -*-

  import cv2

  import numpy as np

  import win32api

  import win32gui

  import win32con

  from PIL import ImageGrab

  import time

  import random

  # 窗体标题 用于定位游戏窗体

  WINDOW_TITLE = "连连看"

  # 时间间隔随机生成 [MIN,MAX]

  TIME_INTERVAL_MAX = 0.06

  TIME_INTERVAL_MIN = 0.1

  # 游戏区域距离顶点的x偏移

  MARGIN_LEFT = 10

  # 游戏区域距离顶点的y偏移

  MARGIN_HEIGHT = 180

  # 横向的方块数量

  H_NUM = 19

  # 纵向的方块数量

  V_NUM = 11

  # 方块宽度

  POINT_WIDTH = 31

  # 方块高度

  POINT_HEIGHT = 35

  # 空图像编号

  EMPTY_ID = 0

  # 切片处理时候的左上、右下坐标:

  SUB_LT_X = 8

  SUB_LT_Y = 8

  SUB_RB_X = 27

  SUB_RB_Y = 27

  # 游戏的最多消除次数

  MAX_ROUND = 200

  def getGameWindow():

   # FindWindow(lpClassName=None, lpWindowName=None) 窗口类名 窗口标题名

   window = win32gui.FindWindow(None, WINDOW_TITLE)

   # 没有定位到游戏窗体

   while not window:

   print(Failed to locate the game window , reposition the game window after 10 seconds...)

   time.sleep(10)

   window = win32gui.FindWindow(None, WINDOW_TITLE)

   # 定位到游戏窗体

   # 置顶游戏窗口

   win32gui.SetForegroundWindow(window)

   pos = win32gui.GetWindowRect(window)

   print("Game windows at " + str(pos))

   return (pos[0], pos[1])

  def getScreenImage():

   print(Shot screen...)

   # 获取屏幕截图 Image类型对象

   scim = ImageGrab.grab()

   scim.save(screen.png)

   # 用opencv读取屏幕截图

   # 获取ndarray

   return cv2.imread("screen.png")

  def getAllSquare(screen_image, game_pos):

   print(Processing pictures...)

   # 通过游戏窗体定位

   # 加上偏移量获取游戏区域

   game_x = game_pos[0] + MARGIN_LEFT

   game_y = game_pos[1] + MARGIN_HEIGHT

   # 从游戏区域左上开始

   # 把图像按照具体大小切割成相同的小块

   # 切割标准是按照小块的横纵坐标

   all_square = []

   for x in range(0, H_NUM):

   for y in range(0, V_NUM):

   # ndarray的切片方法 : [纵坐标起始位置:纵坐标结束为止,横坐标起始位置:横坐标结束位置]

   square = screen_image[game_y + y * POINT_HEIGHT:game_y + (y + 1) * POINT_HEIGHT,

   game_x + x * POINT_WIDTH:game_x + (x + 1) * POINT_WIDTH]

   all_square.append(square)

   # 因为有些图片的边缘会造成干扰,所以统一把图片往内缩小一圈

   # 对所有的方块进行处理 ,去掉边缘一圈后返回

   finalresult = []

   for square in all_square:

   s = square[SUB_LT_Y:SUB_RB_Y, SUB_LT_X:SUB_RB_X]

   finalresult.append(s)

   return finalresult

  # 判断列表中是否存在相同图形

  # 存在返回进行判断图片所在的id

  # 否则返回-1

  def isImageExist(img, img_list):

   i = 0

   for existed_img in img_list:

   # 两个图片进行比较 返回的是两个图片的标准差

   b = np.subtract(existed_img, img)

   # 若标准差全为0 即两张图片没有区别

   if not np.any(b):

   return i

   i = i + 1

   return -1

  def getAllSquareTypes(all_square):

   print("Init pictures types...")

   types = []

   # number列表用来记录每个id的出现次数

   number = []

   # 当前出现次数最多的方块

   # 这里我们默认出现最多的方块应该是空白块

   nowid = 0;

   for square in all_square:

   nid = isImageExist(square, types)

   # 如果这个图像不存在则插入列表

   if nid == -1:

   types.append(square)

   number.append(1);

   else:

   # 若这个图像存在则给计数器 + 1

   number[nid] = number[nid] + 1

   if (number[nid] > number[nowid]):

   nowid = nid

   # 更新EMPTY_ID

   # 即判断在当前这张图中的空白块id

   global EMPTY_ID

   EMPTY_ID = nowid

   print(EMPTY_ID = + str(EMPTY_ID))

   return types

  # 将二维图片矩阵转换为二维数字矩阵

  # 注意因为在上面对截屏切片时是以列为优先切片的

  # 所以生成的record二维矩阵每行存放的其实是游戏屏幕中每列的编号

  # 换个说法就是record其实是游戏屏幕中心对称后的列表

  def getAllSquareRecord(all_square_list, types):

   print("Change map...")

   record = []

   line = []

   for square in all_square_list:

   num = 0

   for type in types:

   res = cv2.subtract(square, type)

   if not np.any(res):

   line.append(num)

   break

   num += 1

   # 每列的数量为V_NUM

   # 那么当当前的line列表中存在V_NUM个方块时我们认为本列处理完毕

   if len(line) == V_NUM:

   print(line);

   record.append(line)

   line = []

   return record

  def canConnect(x1, y1, x2, y2, r):

   result = r[:]

   # 如果两个图像中有一个为0 直接返回False

   if result[x1][y1] == EMPTY_ID or result[x2][y2] == EMPTY_ID:

   return False

   if x1 == x2 and y1 == y2:

   return False

   if result[x1][y1] != result[x2][y2]:

   return False

   # 判断横向连通

   if horizontalCheck(x1, y1, x2, y2, result):

   return True

   # 判断纵向连通

   if verticalCheck(x1, y1, x2, y2, result):

   return True

   # 判断一个拐点可连通

   if turnOnceCheck(x1, y1, x2, y2, result):

   return True

   # 判断两个拐点可连通

   if turnTwiceCheck(x1, y1, x2, y2, result):

   return True

   # 不可联通返回False

   return False

  def horizontalCheck(x1, y1, x2, y2, result):

   if x1 == x2 and y1 == y2:

   return False

   if x1 != x2:

   return False

   startY = min(y1, y2)

   endY = max(y1, y2)

   # 判断两个方块是否相邻

   if (endY - startY) == 1:

   return True

   # 判断两个方块通路上是否都是0,有一个不是,就说明不能联通,返回false

   for i in range(startY + 1, endY):

   if result[x1][i] != EMPTY_ID:

   return False

   return True

  def verticalCheck(x1, y1, x2, y2, result):

   if x1 == x2 and y1 == y2:

   return False

   if y1 != y2:

   return False

   startX = min(x1, x2)

   endX = max(x1, x2)

   # 判断两个方块是否相邻

   if (endX - startX) == 1:

   return True

   # 判断两方块儿通路上是否可连。

   for i in range(startX + 1, endX):

   if result[i][y1] != EMPTY_ID:

   return False

   return True

  def turnOnceCheck(x1, y1, x2, y2, result):

   if x1 == x2 or y1 == y2:

   return False

   cx = x1

   cy = y2

   dx = x2

   dy = y1

   # 拐点为空,从第一个点到拐点并且从拐点到第二个点可通,则整条路可通。

   if result[cx][cy] == EMPTY_ID:

   if horizontalCheck(x1, y1, cx, cy, result) and verticalCheck(cx, cy, x2, y2, result):

   return True

   if result[dx][dy] == EMPTY_ID:

   if verticalCheck(x1, y1, dx, dy, result) and horizontalCheck(dx, dy, x2, y2, result):

   return True

   return False

  def turnTwiceCheck(x1, y1, x2, y2, result):

   if x1 == x2 and y1 == y2:

   return False

   # 遍历整个数组找合适的拐点

   for i in range(0, len(result)):

   for j in range(0, len(result[1])):

   # 不为空不能作为拐点

   if result[i][j] != EMPTY_ID:

   continue

   # 不和被选方块在同一行列的不能作为拐点

   if i != x1 and i != x2 and j != y1 and j != y2:

   continue

   # 作为交点的方块不能作为拐点

   if (i == x1 and j == y2) or (i == x2 and j == y1):

   continue

   if turnOnceCheck(x1, y1, i, j, result) and (

   horizontalCheck(i, j, x2, y2, result) or verticalCheck(i, j, x2, y2, result)):

   return True

   if turnOnceCheck(i, j, x2, y2, result) and (

   horizontalCheck(x1, y1, i, j, result) or verticalCheck(x1, y1, i, j, result)):

   return True

   return False

  def autoRelease(result, game_x, game_y):

   # 遍历地图

   for i in range(0, len(result)):

   for j in range(0, len(result[0])):

   # 当前位置非空

   if result[i][j] != EMPTY_ID:

   # 再次遍历地图 寻找另一个满足条件的图片

   for m in range(0, len(result)):

   for n in range(0, len(result[0])):

   if result[m][n] != EMPTY_ID:

   # 若可以执行消除

   if canConnect(i, j, m, n, result):

   # 消除的两个位置设置为空

   result[i][j] = EMPTY_ID

   result[m][n] = EMPTY_ID

   print(Remove : + str(i + 1) + , + str(j + 1) + and + str(m + 1) + , + str(

   n + 1))

   # 计算当前两个位置的图片在游戏中应该存在的位置

   x1 = game_x + j * POINT_WIDTH

   y1 = game_y + i * POINT_HEIGHT

   x2 = game_x + n * POINT_WIDTH

   y2 = game_y + m * POINT_HEIGHT

   # 模拟鼠标点击第一个图片所在的位置

   win32api.SetCursorPos((x1 + 15, y1 + 18))

   win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x1 + 15, y1 + 18, 0, 0)

   win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x1 + 15, y1 + 18, 0, 0)

   # 等待随机时间 ,防止检测

   time.sleep(random.uniform(TIME_INTERVAL_MIN, TIME_INTERVAL_MAX))

   # 模拟鼠标点击第二个图片所在的位置

   win32api.SetCursorPos((x2 + 15, y2 + 18))

   win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x2 + 15, y2 + 18, 0, 0)

   win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x2 + 15, y2 + 18, 0, 0)

   time.sleep(random.uniform(TIME_INTERVAL_MIN, TIME_INTERVAL_MAX))

   # 执行消除后返回True

   return True

   return False

  def autoRemove(squares, game_pos):

   game_x = game_pos[0] + MARGIN_LEFT

   game_y = game_pos[1] + MARGIN_HEIGHT

   # 重复一次消除直到到达最多消除次数

   while True:

   if not autoRelease(squares, game_x, game_y):

   # 当不再有可消除的方块时结束 , 返回消除数量

   return

  if __name__ == __main__:

   random.seed()

   # i. 定位游戏窗体

   game_pos = getGameWindow()

   time.sleep(1)

   # ii. 获取屏幕截图

   screen_image = getScreenImage()

   # iii. 对截图切片,形成一张二维地图

   all_square_list = getAllSquare(screen_image, game_pos)

   # iv. 获取所有类型的图形,并编号

   types = getAllSquareTypes(all_square_list)

   # v. 讲获取的图片地图转换成数字矩阵

   result = np.transpose(getAllSquareRecord(all_square_list, types))

   # vi. 执行消除 , 并输出消除数量

   print(The total elimination amount is + str(autoRemove(result, game_pos)))

  

  兄弟们快去试试吧

  以上就是Python实现自动玩连连看的脚本分享的详细内容,更多关于Python连连看的资料请关注盛行IT软件开发工作室其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: