c# 實(shí)現(xiàn)自動(dòng)掃雷
年前無(wú)意看到一個(gè)用Python寫的小桌面程序,可以自動(dòng)玩掃雷的游戲,覺得挺有意思,決定用C#也做一個(gè)?!菊鎸?shí)情況是:我知道Python最近比較火,非常適合搞爬蟲、大數(shù)據(jù)、機(jī)器學(xué)習(xí)之類的,但現(xiàn)在連桌面程序都用Python做了嗎?還給不給.NET程序員活路了?簡(jiǎn)直不能忍!】
春節(jié)期間正好有閑就搞了一下,先下載了一個(gè)第三方的掃雷游戲,實(shí)現(xiàn)功能以后覺得下載的這個(gè)掃雷游戲分辨率太低了,也不好看,所以又自己做了一個(gè)掃雷游戲,湊成一套。
源碼下載地址:https://github.com/seabluescn/AutoMineSweeper
需要提前說明的是,這兩個(gè)程序是獨(dú)立的,之間沒有任何接口與聯(lián)系,自動(dòng)掃雷的程序通過讀取屏幕信息獲取游戲狀態(tài),并模擬鼠標(biāo)操作來進(jìn)行游戲。下面就幾個(gè)相關(guān)技術(shù)點(diǎn)和大家分享一下。
1、獲取應(yīng)用程序窗口
[DllImport("user32.dll")]
private static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect);
private Rect GetWindowRect()
{
Process[] processes = Process.GetProcesses();
Process process = null;
for (int i = 0; i < processes.Length - 1; i++)
{
process = processes[i];
if (process.MainWindowTitle == "MineSweeper")
{
break;
}
}
Rect rect = new Rect();
GetWindowRect(process.MainWindowHandle, out rect);
return rect;
}
2、屏幕截圖
Rect rect = GetWindowRect();
int left = rect.Left;
int top = rect.Top;
int centerleft = 21; //偏移
int centertop = 93;
int centerwidth = 300;
int centerheight = 300;
Bitmap bitmapCenter = new Bitmap(centerwidth, centerheight);
using (Graphics graphics = Graphics.FromImage(bitmapCenter))
{
graphics.CopyFromScreen(left + centerleft, top + centertop, 0, 0, new Size(centerwidth, centerheight));
this.pictureBox1.Image?.Dispose();
this.pictureBox1.Image = bitmapCenter;
}
截圖后,根據(jù)圖片上固定位置的顏色信息判斷該位置的狀態(tài),最終形成一個(gè)數(shù)組。
3、模擬鼠標(biāo)點(diǎn)擊
[DllImport("user32")]
private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
const int MOUSEEVENTF_MOVE = 0x0001; //移動(dòng)鼠標(biāo)
const int MOUSEEVENTF_LEFTDOWN = 0x0002; //模擬鼠標(biāo)左鍵按下
const int MOUSEEVENTF_LEFTUP = 0x0004; //模擬鼠標(biāo)左鍵抬起
const int MOUSEEVENTF_RIGHTDOWN = 0x0008; //模擬鼠標(biāo)右鍵按下
const int MOUSEEVENTF_RIGHTUP = 0x0010; //模擬鼠標(biāo)右鍵抬起
const int MOUSEEVENTF_MIDDLEDOWN = 0x0020; //模擬鼠標(biāo)中鍵按下
const int MOUSEEVENTF_MIDDLEUP = 0x0040; //模擬鼠標(biāo)中鍵抬起
const int MOUSEEVENTF_ABSOLUTE = 0x8000; //標(biāo)示是否采用絕對(duì)坐標(biāo)
int clickPointX = X * 65535 / Screen.PrimaryScreen.Bounds.Width;
int clickPointY = Y * 65535 / Screen.PrimaryScreen.Bounds.Height;
//移動(dòng)鼠標(biāo)
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, clickPointX, clickPointY, 0, 0);
//左鍵點(diǎn)擊
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
//右鍵點(diǎn)擊
mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
4、游戲算法
獲得游戲狀態(tài)后,需要判斷下一步操作,是點(diǎn)開某個(gè)位置還是右鍵標(biāo)記某個(gè)位置,算法循環(huán)遍歷所有方塊,一共三步:
1)基礎(chǔ)算法
基礎(chǔ)算法1:對(duì)于已經(jīng)翻開的塊,中心數(shù)字和周圍已經(jīng)標(biāo)記的雷數(shù)一致,其周圍所有未知位置都不是雷,左鍵點(diǎn)開
基礎(chǔ)算法2:對(duì)于已經(jīng)翻開的塊,中心數(shù)字=未知位置數(shù)量+周圍已經(jīng)標(biāo)記的雷數(shù) :其周圍所有未知位置均為雷,右鍵標(biāo)記
2)高一級(jí)算法
先計(jì)算所有已翻開的塊,其周圍未知塊含雷的數(shù)量之和。
算法1:對(duì)于已經(jīng)翻開的塊,如果周圍未知塊超過2個(gè),其中有一個(gè)未知塊:中心數(shù)字-雷==其他位置塊組合雷數(shù)總和:該未知塊必不是雷
算法2:對(duì)于已經(jīng)翻開的塊,如果周圍未知塊超過2個(gè),其中有一個(gè)未知塊:數(shù)字-雷-其他位置塊組合雷數(shù)=1:該未知塊必是雷
3)實(shí)在沒有找到合適的點(diǎn),只能隨機(jī)點(diǎn)開
對(duì)所有未知的點(diǎn),計(jì)算一下周圍雷的概率,選擇概率最小的點(diǎn)開。
經(jīng)測(cè)試,程序?qū)δ繕?biāo)狀態(tài)的識(shí)別率為100%,智能程度還不錯(cuò),比一般人玩的好,無(wú)聊時(shí)可以看它玩一天。
以上就是c# 實(shí)現(xiàn)自動(dòng)掃雷的詳細(xì)內(nèi)容,更多關(guān)于c# 掃雷的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c#創(chuàng)建windows服務(wù)(Windows Services)詳細(xì)步驟
這篇文章主要介紹了c#創(chuàng)建windows服務(wù)(Windows Services)詳細(xì)步驟,大家參考使用吧2013-12-12
C#?DateTime.Now.ToString()?用法示例講解
這篇文章主要介紹了C#?DateTime.Now.ToString()?用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01
C#基于OLEDB獲取Excel文件表結(jié)構(gòu)信息的方法
這篇文章主要介紹了C#基于OLEDB獲取Excel文件表結(jié)構(gòu)信息的方法,結(jié)合實(shí)例形式分析了OLEDB的調(diào)用及Excel的相關(guān)操作技巧,需要的朋友可以參考下2017-05-05

