c# 实现自动扫雷
作者:seabluescn 发布时间:2021-09-01 09:25:58
年前无意看到一个用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%,智能程度还不错,比一般人玩的好,无聊时可以看它玩一天。
来源:https://www.cnblogs.com/seabluescn/p/10522627.html


猜你喜欢
- 简单介绍下功能1.每隔一段时间(比如1分钟)在京东手机每日一秒杀页面提取产品(手机)链接。 http://sale.360buy.com/a
- 对于分布式应用来说,最开始遇到的问题就是 session 的存储了,解决方案大致有如下几种使用 spring-session 它可以把 se
- 方式一:在gradle.properties中写入:#测试环境ENV_TEST=test#开发环境ENV_DEV=dev#生产环境ENV_O
- Java Boolean 初始化方式1、Boolean(String boolString);以字符串的方式初始化,只有当字符串是“true
- 目录或库文件名中包含汉字或空格的话,请将其用半角双引号括住。项目、属性、C/C++、附加包含目录:填写附加头文件所在目录 分号间隔多项项目、
- 本文将向大家展示如何拍照截图。先看看效果图:拍照截图有点儿特殊,要知道,现在的Android智能手机的摄像头都是几百万的像素,拍出来的图片都
- 抛出问题:Long a = 4l;Long b = 4l;a == b //trueLong a = 128l;Long b = 128l;
- 1. RocketMQ Topic创建机制以下源码基于Rocket MQ 4.7.0RocketMQ Topic创建机制分为两种:一种自动创
- 一、说明标准库提供了许多容器,它们有一个共同点:它们是同类的。也就是说,标准库中的容器只能存储一种类型的元素。 std::vector<
- 整理文档,搜刮出一个android 通过MediaRecorder实现简单的录音示例,稍微整理精简一下做下分享。MainActivitypa
- 本文介绍了Android:利用SharedPreferences实现自动登录,具体如下:主要代码:public class LoginAct
- 实践过程效果代码public partial class Form1 : Form{ public Form1()
- 本文实例讲述了Android编程实现等比例显示图片的方法。分享给大家供大家参考,具体如下:在android中,由于密度的影响,如果想得到图片
- 用户在注册网站信息的时候基本上都要数据验证码验证。那么图片验证码功能该如何实现呢?大概步骤是:1.在内存中创建缓存图片2.设置背景色3.画边
- Android 如何修改APK的默认名称用Android Studio 打包App时生成的名称默认是 app-release.apk(已签名
- SpringBoot的主要目的是简化配置文件,通过少量配置即可运行Java程序,其强大的自动配置功能帮助开发者轻松实现配置装配,通过引入Sp
- 1 使用阿里的FastJson1.1 项目的pom.xml依赖<dependency> <groupId>com.a
- 总结并复现了一下Unsafe在安全领域的一些应用0 前言unsafe里面有很多好用的方法,比如allocateInstance可以直接创建实
- 首先定义布局文件:<?xml version="1.0" encoding="utf-8"?&
- 目录源码实现基本流程ThreadLoalMap数据结构Hash冲突及解决ThreadLocal内存泄露内存引用链路引用类型为什么使用弱引用而