这个算是除了课程设计之外我的第一个小工具,这里重点分析一下思路,有基础的读者应该可以通过参考本文章写出自己的程序。
注:此文章仅用于学习参考
一、 需要的知识:
二、 程序实现原理步骤:
- 获取游戏及图片信息
- 分析图片及定位将其转化为矩阵(二维数组)
- 通过BFS算法计算消除顺序
- 发送对应鼠标信息进行消除。
三、 分步说明
1. 使用的结构体与参数说明:
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
| struct PointDir { int x; int y; int step; int dir; };
class Color { public: unsigned char R; unsigned char G; unsigned char B; Color(); Color(int r, int g, int b); void operator=(COLORREF c); bool operator==(Color &c); bool operator!=(Color &c); void displayRGBInfo(); };
class Block { public: Color rect[blockSizeY][blockSizeX]; Block(); bool operator==(Block &b); };
static const int radious;
static const int windowX; static const int windowY;
static const int raceX = xx + radious; static const int raceY = xx + radious;
static const int sizeX; static const int sizeY;
static const int blockSizeX = xx - radious * 2; static const int blockSizeY = xx - +radious * 2;
static const int blank = xx + radious * 2;
|
2. 对图像的截取:
1 2 3 4 5 6 7 8 9 10
| HWND FindWindow(LPCSTR lpClassName, LPCSTR lpWindowName);
BOOL WINAPI SetWindowPos(HWND,HWND hWndInsertAfter,int X,int Y,int cx,_In_ int cy, UINT uFlags);
HDC GetDC(HWND);
COLORREF GetPixel(HDC hdc, int X, int Y);
SetForegroundWindow(hwnd);
|
以窗口名称查找游戏窗口得到对应句柄,激活窗口,设置窗口位置(可省,仅便于计算像素点位置)。手动计算得出牌面上每个方块的像素位置,对每个方块截取像素并保存在相应结构体数组内。
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
| HWND hwnd=NULL cout << "正在查找窗口 <<游戏窗口名称>>..." << endl; while (hwnd == NULL) { hwnd = FindWindow(NULL, TEXT("游戏窗口名称")); } cout << "窗口已找到" << endl; cout << "设置窗口位置" << endl; SetWindowPos(hwnd, HWND_TOP, windowX, windowY, 0, 0, SWP_NOSIZE); SetForegroundWindow(hwnd); }
cout << "获取方块信息..." << endl;
HDC hdc = GetDC(hwnd); Block block[sizeY][sizeX];
for (int row = 0; row < sizeY; row++) { for (int col = 0; col < sizeX; col++) { cout << "正在获取block[" << row << "][" << col << "]方块信息..." << endl; for (int i = 0; i < blockSizeY; i++) { for (int j = 0; j < blockSizeX; j++) { block[row][col].rect[i][j] = GetPixel(hdc, raceX + col * (blockSizeX + blank) + j, raceY + row * (blockSizeY + blank) + i); } } } }
|
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
| Block space; for (int i = 0; i < blockSizeY; i++) { for (int j = 0; j < blockSizeX; j++) { space.rect[i][j].R = xx; space.rect[i][j].G = xx; space.rect[i][j].B = xx; } }
int cnt = 1; Block pblock[50]; pblock[0] = space;
for (int i = 0; i < sizeY; i++) { for (int j = 0; j < sizeX; j++) { bool flag = false; for (int k = 0; k < cnt; k++) { if (k == 49) { cout << "error!牌面数量太多!" << endl; exit(1); } if (block[i][j] == pblock[k]) { map[i][j] = k; flag = true; break; } } if (!flag) { pblock[cnt] = block[i][j]; map[i][j] = cnt; cnt++; } } }
|
4. 消除路径分析:
算法使用BFS广度优先搜索,对每个未消除方块展开搜索,此处注意连连看限制条件(拐点不超过2个)将待消除方块信息(鼠标点击的坐标)保存在一个队列中。
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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
bool bfs(int inX, int inY, int &ansX, int &ansY) { PointDir inp, curp, nextp; inp.x = inX; inp.y = inY; inp.step = -1; inp.dir = -1;
queue<PointDir> q; curp = inp; q.push(curp); bool isFind = false; while (!q.empty() && isFind == false) { curp = q.front(); q.pop(); for (int k = 0; k < 4; k++) { nextp.x = curp.x + dirs[k][0]; nextp.y = curp.y + dirs[k][1]; nextp.dir = k; nextp.step = curp.step; if (curp.dir != k) { nextp.step++; } if (nextp.step > 2) { continue; } if (nextp.x == inp.x && nextp.y == inp.y) { continue; } if ((nextp.x >= 0) && (nextp.x < sizeX) && (nextp.y >= 0) && (nextp.y < sizeY)) { if (map[nextp.y][nextp.x] == 0) { q.push(nextp); } if (map[nextp.y][nextp.x] == map[inp.y][inp.x]) { map[inp.y][inp.x] = 0; map[nextp.y][nextp.x] = 0; ansX = nextp.x; ansY = nextp.y; isFind = true; break; } } } } return isFind; }
void caculate() { for (int k = 0; k < 5; k++) { if (checkOver()) { break; } for (int i = 0; i < sizeY; i++) { for (int j = 0; j < sizeX; j++) { if (map[i][j] != 0) { PointDir p1; p1.x = j; p1.y = i; PointDir p2; if (bfs(j, i, p2.x, p2.y)) { qClick.push(p1); qClick.push(p2); } } } } } }
|
5.消除的实现:
1 2 3 4
| BOOL SetCursorPos(int X, int Y);
void mouse_event(DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo);
|
按照待消除队列依次模拟鼠标移动点击消除便是。
1 2 3 4 5 6 7 8 9 10 11 12
| while (!qClick.empty()) { PointDir p; p = qClick.front(); SetCursorPos(windowX + raceX + p.x * (blockSizeX + blank), windowY + raceY + p.y * (blockSizeY + blank)); mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); Sleep(10); mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); qClick.pop(); }
|