臭虫?好东西!
图像识别与自动化
[又是踩坑记]
近日,某大作战出了一款活动(或许好久之前了)鼓励玩家观看广告,
我一看怎么这么智障,按键精灵秒过
然后我错了
蒟蒻生气了,开始没事找事,召唤出了瑟瑟发抖的devc++……大战一星期(确实很慢),今日完工。1000lines,一日可上4级
唉。这就是我为何蒟蒻都比不上了,正经算法不怎么学,奇怪的东西特别感兴趣,各种奇怪的小程序小插件,包括之前气得死去活来的xlnt库,也就是一个统计作业的任务,可是竟然也编不出了?电脑炸了是个原因,VS装不上(???),但是,其他踩过的坑一个不记得,之前的两篇踩坑记仅仅冰山一角。
于是现在xlnt库的研究的唯一作用
– 喏,这就是那个谁。 --啊!就是那个统计作业程序那个人对吧
回头一看,我连中文转换(StringToUTF8
,我的电脑太差所以要,不然xlnt当场乱码)都忘了,再想,之前的程序里面的bug一个都没记下来,反反复复地踩。不行,好歹不能被臭虫欺负。臭虫入库计划现在开始。
真正的标题:《使用C++自动识别和观看广告》
- 闲话结束
#1 揭掉GetPixel的乌龟壳
(GetPixel太慢了)
众所周知,废话不说。下面的语句可以显著加速。但是,这极可能是win7的锅,因为Uxsms本来是一个服务,提供桌面视觉效果
system("sc stop Uxsms");
(说实话,我打游戏的时候都会把它停掉,内存贼大)
执行1000次GetPixel耗时
运行前17746ms,运行后73ms
(不言而喻)
#2 undefined reference to `__imp_TextOutA’
本来想添加一个新的窗口,那么得会说话才行
解决方法:"编译时加入以下命令"勾!
输入 -mwindows
注意事项:这个参数会在程序开始时不显示控制台窗口,酌情采用叭
#3 undefined reference to `__imp_GetPixel’
同上,"编译时加入以下命令"勾!
输入 -lgdi32
目前来看,没有副作用
#4 define的奇怪行为
一个老臭虫,老踩qwq
如果要用#ifdef #ifndef #else #endif之类的话,那么#define的必须是个左右都带有_的字符串
原因不明…?
[ x ]#define DEBUG//编译通过,但无法使用#ifdef
[ √ ]#define _DEBUG_
#5 初始化错误
也是老臭虫
int rm1[32][32]={};
int rm2[32][32]={0};
int rm3[32][32]={{}};
int rm4[32][32]={{0}};
//等价的,全初始化为0
int rm5[32][32]={1}
int rm6[32][32]={{1}}
//你太懒了,需要被制裁(只有第一个会变1)
#6 不可预料的行为
这是一个概括性的说法,例如无论运行多少次都输出相同结果,消失的参数,奇怪的运算,这里我提一个非常容易忘记的可能性
你的变量初始化了吗?
例如char*的malloc,hDC的申请与释放,iostream被close之类
哦提到一件有趣的事,GetPixel在程序调用过多以后会变傻,具体表现就是Get出来都是4294967295(2^33-1,long),这时候只要ReleaseDC再重新GetDC马上就能解决,所以最好不要一个HDC用到底
#7 某线程卡死
- 原因1:CPU太非
其实追根溯源,多线程只不过是CPU在多个工作之间左右横跳罢了,只有多核CPU才是真正的多线程执行,切换需要时间,保存的程序需要堆栈,而且下一步干哪个线程的活完全随机,所以一个线程跑了一圈,另一个才跑了一步是非常正常的。
有什么办法呢?一种就是不开多线程(这显然很慢),另一种就是使用公共变量手动同步。好像很好?但时间上甚至更慢,因为CPU执行的顺序并没有改变,还额外执行了一堆判断和Sleep
那么最好的方法是什么?合理地开线程,太多了也不好,例如我试过一个线程跑12个格子,跑一圈10s;开三个,每个四格,全部刷出来只要3-5s(有点运气成分)
- 原因2:没开出来
这其实是非常好判断的,如果一边跑了三五圈另一边一点动静没有,那就是没开到。
下面这段语句假如没有Sleep(200),情况就会十分滑稽,有时候i=1,2相应;有时候I=3相应,有时候一个都不响应(的确试过??)
for (int i=0;i<3;i++)
{
dat tmpdat=(dat){i};
pthread_create(&tidd[i],NULL,ref,&tmpdat);
Sleep(200);//划重点
}
#8 位运算
优先级 | 运算符举例 | 备注 |
---|---|---|
15 | () [] -> . | 这不好概括 |
14 | ! ~ ++ -- | 前缀运算符 |
13 | * / % | |
12 | + - | |
11 | << >> | |
10 | >< | 关系运算符 |
9 | == != | |
8 | & | |
7 | ^ | |
6 | | | |
5 | && | 逻辑运算符 |
4 | || | |
3 | ?: | 条件运算符 |
2 | = *= += <<= &= | 赋值运算符 |
1 | , | 逗号 |
注意位运算分别位于14,8,7,6和2这五个优先级
(但,加上括号就绝对没事)
下面就是典型的人类迷惑行为示范
for (int i=0;i<rand()&7;i++)
if(rand()&7==5)
...
#9 字母快捷键
这是用来提醒我自己的,我觉得应该没人会像我那么…
KEY_DOWN()是不分大小写的
[ √ ]KEY_DOWN('A');
[ √ ]KEY_DOWN('0');
[ x ]KEY_DOWN('a');
下面吐槽我的垃圾编程习惯
#1 Ctrl+C
如果你按了很多次这个键,你应该本能提醒自己开函数
显然,每按一次,臭虫也跟着它复制了一次
常数也是这样,宁肯define,不然改起来就很难受了
#2 不用注释
第二天你开始回忆这句话到底是什么意思
#3 干嘛不用手
花费几天时间调一个可能一天才出现一两次的情况
(干嘛不用手?)
#4 调试的艺术
调试有两种,一种叫断点调试,另一种叫人脑调试。
很明显,人脑调试可以大程度上优化程序结构来排除潜在臭虫,也能够避免“不可预料的行为”的误导,但你的时间真的不多,该断点的还是得。
#5 左右开弓
写了一些拿来F11,然后一边调试一边继续完善,我称之为左右开弓。评价:糟糕
这个方法整掉我好多时间,可惜蒟蒻还是太浮躁了呢
一些思想
#1 手动数字识别和识别精度
这个活动有一个基本任务,把数字相同的道具拖到一起。
数字圈长这个样子,33x33px
-
检测33x33px矩阵中符合2384593的颜色(R209 G98 B36)像素,和示例进行比较
- 评价:太慢(1个格子1000次GetPixel)
- 评价:太慢(1个格子1000次GetPixel)
-
检测示例中含有2384593颜色的格子与屏幕上是否符合,统计错误数,并且记忆化已经获取过的像素
- 评价:容错太低识别不出来,因为示例带有偶然性,不同位置轻微差别;容错太高又辨识度不高,例如18和19、20和26混为一谈(此时最合适容错率18px)
- 评价:容错太低识别不出来,因为示例带有偶然性,不同位置轻微差别;容错太高又辨识度不高,例如18和19、20和26混为一谈(此时最合适容错率18px)
-
检测所有位置的示例中符合2384593的格子并叠加,叠加数达到8以上的作为关键参照物
- 评价:(不言而喻)关键参照容错率可以调5px
- 评价:(不言而喻)关键参照容错率可以调5px
#2 自己动手丰衣足食
怎么又是这句对于按键精灵这类东西,即便不上OD,DevC++都是可以完全取代的了,但更重要的是有一个清醒的、随机应变,think out of the box的大脑,这些小插件,用处不大,活儿干完就废了,但我的脑子和c++做到了很多无法想象的事,整理定制版六级词库、批量处理文件等等,让我感到此生无悔入OI。。。
不过,我debug浪费的时间够多了,应该没人像我一样为了这样一个两个月的奇怪活动…仔细想想,这个游戏也没什么意思,只能权当踩坑…权当踩坑了。。所以啊一个程序不管干游戏还是干啥,总有个原则,投资自己总是最靠谱的,每个人拥有的最好的礼物都是Reality。