一個掃雷游戲和一個自動玩掃雷游戲的程序


    年前無意看到一個用Python寫的小桌面程序,可以自動玩掃雷的游戲,覺得挺有意思,決定用C#也做一個。【真實情況是:我知道Python最近比較火,非常適合搞爬蟲、大數據、機器學習之類的,但現在連桌面程序都用Python做了嗎?還給不給.NET程序員活路了?簡直不能忍!】

   春節期間正好有閑就搞了一下,先下載了一個第三方的掃雷游戲,實現功能以后覺得下載的這個掃雷游戲分辨率太低了,也不好看,所以又自己做了一個掃雷游戲,湊成一套。

    源碼下載地址:https://github.com/seabluescn/AutoMineSweeper

    需要提前說明的是,這兩個程序是獨立的,之間沒有任何接口與聯系,自動掃雷的程序通過讀取屏幕信息獲取游戲狀態,並模擬鼠標操作來進行游戲。下面就幾個相關技術點和大家分享一下。

 

1、獲取應用程序窗口

       [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;
            }

截圖后,根據圖片上固定位置的顏色信息判斷該位置的狀態,最終形成一個數組。

 

3、模擬鼠標點擊

        [DllImport("user32")]
        private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

        const int MOUSEEVENTF_MOVE = 0x0001; //移動鼠標
        const int MOUSEEVENTF_LEFTDOWN = 0x0002; //模擬鼠標左鍵按下
        const int MOUSEEVENTF_LEFTUP = 0x0004; //模擬鼠標左鍵抬起
        const int MOUSEEVENTF_RIGHTDOWN = 0x0008; //模擬鼠標右鍵按下
        const int MOUSEEVENTF_RIGHTUP = 0x0010; //模擬鼠標右鍵抬起
        const int MOUSEEVENTF_MIDDLEDOWN = 0x0020; //模擬鼠標中鍵按下
        const int MOUSEEVENTF_MIDDLEUP = 0x0040; //模擬鼠標中鍵抬起
        const int MOUSEEVENTF_ABSOLUTE = 0x8000; //標示是否采用絕對坐標

                int clickPointX = X * 65535 / Screen.PrimaryScreen.Bounds.Width;
                int clickPointY = Y * 65535 / Screen.PrimaryScreen.Bounds.Height;

               //移動鼠標
                mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, clickPointX, clickPointY, 0, 0);

                //左鍵點擊
                mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                
               //右鍵點擊
                mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
                

 

4、游戲算法

獲得游戲狀態后,需要判斷下一步操作,是點開某個位置還是右鍵標記某個位置,算法循環遍歷所有方塊,一共三步:

1)基礎算法

基礎算法1:對於已經翻開的塊,中心數字和周圍已經標記的雷數一致,其周圍所有未知位置都不是雷,左鍵點開

基礎算法2:對於已經翻開的塊,中心數字=未知位置數量+周圍已經標記的雷數 :其周圍所有未知位置均為雷,右鍵標記

2)高一級算法

先計算所有已翻開的塊,其周圍未知塊含雷的數量之和。

算法1:對於已經翻開的塊,如果周圍未知塊超過2個,其中有一個未知塊:中心數字-雷==其他位置塊組合雷數總和:該未知塊必不是雷

算法2:對於已經翻開的塊,如果周圍未知塊超過2個,其中有一個未知塊:數字-雷-其他位置塊組合雷數=1:該未知塊必是雷

3)實在沒有找到合適的點,只能隨機點開

對所有未知的點,計算一下周圍雷的概率,選擇概率最小的點開。

 

經測試,程序對目標狀態的識別率為100%,智能程度還不錯,比一般人玩的好,無聊時可以看它玩一天。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM