連連看類遊戲核心在於「尋找可由不超過三條直線連接的相同圖案對」。本文示範如何在 VC++ 6.0 中,透過視窗截圖、色彩特徵碼識別棋盤格狀、實作尋路演算法、模擬滑鼠點擊,完成一個半自動外掛程式。文中涵蓋畫面辨識、資料結構設計、BFS 尋路與輸入模擬關鍵技術。
struct MYCOLOR { COLORREF c[4]; }; // 每格 4 採樣點
MYCOLOR tc[230]; // 色彩指紋庫
int map[19][11]; // 邏輯棋盤
int tcnum = 1; // 索引計數,0 保留給空格
void CZg1Dlg::OnButton3() // 「編碼/辨識」按鈕
{
int tX[4] = {15,11,15,21}; // 相對 X 偏移
int tY[4] = {17,17,21,17}; // 相對 Y 偏移
CPoint base(10, 180); // 棋盤左上角
CDC* pDC = m_gameWnd->GetDC();
for (int row = 0; row < 11; ++row)
{
for (int col = 0; col < 19; ++col)
{
MYCOLOR tmp;
for (int k = 0; k < 4; ++k)
tmp.c[k] = pDC->GetPixel(base.x + col*31 + tX[k], base.y + row*35 + tY[k]);
// 簡易背景色過濾(依實際遊戲調整 RGB 範圍)
bool isBg = true;
for (int k = 0; k < 4; ++k) {
int r = GetRValue(tmp.c[k]), g = GetGValue(tmp.c[k]), b = GetBValue(tmp.c[k]);
if (!((r>45&&r<73) && (g>50&&g<90) && (b>103&&b<129))) { isBg = false; break; }
}
if (isBg) { map[col][row] = 0; continue; }
// 查找或新增指紋
int idx = -1;
for (int i = 1; i < tcnum; ++i)
if (memcmp(&tc[i], &tmp, sizeof(MYCOLOR)) == 0) { idx = i; break; }
if (idx == -1) { tc[tcnum] = tmp; idx = tcnum++; }
map[col][row] = idx;
}
}
m_gameWnd->ReleaseDC(pDC);
}
struct Node { int x, y, dir, turns; };
bool CanLink(int x1, int y1, int x2, int y2)
{
if (map[x1][y1] == 0 || map[x1][y1] != map[x2][y2]) return false;
const int dx[4] = {0,0,1,-1}, dy[4] = {1,-1,0,0};
bool vis[21][13][4][4] = {}; // x,y,dir,turns
queue q;
// 從起點四個方向展開
for (int d = 0; d < 4; ++d) {
int nx = x1 + dx[d], ny = y1 + dy[d];
if (nx>=0 && nx<19 && ny>=0 && ny<11 && (map[nx][ny]==0 || (nx==x2&&ny==y2)))
q.push({nx,ny,d,0}), vis[nx][ny][d][0]=true;
}
while (!q.empty()) {
Node cur = q.front(); q.pop();
if (cur.x == x2 && cur.y == y2) return true;
for (int d = 0; d < 4; ++d) {
int nx = cur.x + dx[d], ny = cur.y + dy[d];
int nt = cur.turns + (d != cur.dir);
if (nt > 3) continue; // 最多 3 線段 = 2 轉彎
if (nx<0||nx>=19||ny<0||ny>=11) continue;
if (map[nx][ny]!=0 && !(nx==x2&&ny==y2)) continue;
if (vis[nx][ny][d][nt]) continue;
vis[nx][ny][d][nt] = true;
q.push({nx,ny,d,nt});
}
}
return false;
}
void CZg1Dlg::OnAutoPlay()
{
for (int y1 = 0; y1 < 11; ++y1)
for (int x1 = 0; x1 < 19; ++x1)
if (map[x1][y1])
for (int y2 = 0; y2 < 11; ++y2)
for (int x2 = 0; x2 < 19; ++x2)
if (map[x2][y2] && CanLink(x1,y1,x2,y2))
{
ClickCell(x1, y1);
ClickCell(x2, y2);
map[x1][y1] = map[x2][y2] = 0; // 更新邏輯地圖
goto NEXT_ROUND; // 重新掃描
}
return;
NEXT_ROUND:
OnAutoPlay(); // 遞迴或改用 while 迴圈
}
void ClickCell(int cx, int cy)
{
// 格子中心螢幕座標
int sx = gameRect.left + 10 + cx*31 + 15;
int sy = gameRect.top + 180 + cy*35 + 17;
SetCursorPos(sx, sy);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0,0,0,0);
Sleep(30);
mouse_event(MOUSEEVENTF_LEFTUP, 0,0,0,0);
Sleep(50);
}
本文從像素級色彩辨識、邏輯建模、圖論尋路到輸入模擬,完整展示了遊戲外掛的核心技術棧。雖然針對特定版本 QQ 連連看,但方法論可移植至任意同類型連連看遊戲。開發過程中深入體會了影像處理、演算法設計與系統程式設計的交叉應用,極具教學價值。