当前位置: 移动技术网 > IT编程>开发语言>.net > 一个扫雷游戏和一个自动玩扫雷游戏的程序

一个扫雷游戏和一个自动玩扫雷游戏的程序

2019年03月14日  | 移动技术网IT编程  | 我要评论

女人体艺术,书虫成神记,健康之路20131107

    年前无意看到一个用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%,智能程度还不错,比一般人玩的好,无聊时可以看它玩一天。

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网