背景实现思路python实现C语言实现C版细节C语言版测试结果result
背景从网上找到一个开源小游戏,经过删改简化,变成方块自己下落,点击最下一行红色方块即可消除,逐层下落,限时20s尽可能多但不准错.
所有文件可查看下面链接:
链接:资源
提取码:q6p8
经过观察,我们发现能点击的那一层,中心坐标大概在y轴725的直线上
(点击开始后)
这时候,可以通过调查屏幕对应坐标处的像素点的颜色是否是红色的(如图的红色),是的话,就点击。
在这里依次判断四个位置,把x坐标带进去,y坐标始终是725
(测试屏幕坐标的方法,可以用pyautogui库,后台开一个cmd运行python,执行pyautogui.position(),打印当前鼠标坐标,利用这一方法,可将鼠标放在需要的位置,然后切屏,运行,得到坐标点)
from ctypes import * # 获取屏幕上某个坐标的颜色 gdi32 = windll.gdi32 user32 = windll.user32 def getC(): if gdi32.GetPixel(user32.GetDC(None), 600, 725) & 0x0000ff == 237: return 600 if gdi32.GetPixel(user32.GetDC(None), 825, 725) & 0x0000ff == 237: return 825 if gdi32.GetPixel(user32.GetDC(None), 1080, 725) & 0x0000ff == 237: return 1080 if gdi32.GetPixel(user32.GetDC(None), 1325, 725) & 0x0000ff == 237: return 1325 # positions = [(600, 725), (825, 725), (1080, 725), (1325, 725)] from time import sleep from threading import Thread import pyautogui as pg can_continue = True def count_time(): sleep(20) can_continue = False def main(): # 切屏及开始时间 sleep(1) Thread(target=count_time).start() while can_continue: # 计时器已启动 pg.click(getC(), 725) if __name__ == "__main__": main()
这是已经优化过的,程序解读主要是,开启一个子线程用来计时,防止程序一直 *** 作鼠标导致系统无法使用
然后getC()函数原本是获取RGB的,为了尽可能提高运行速度,改成直接返回x坐标,这样就免去了又一次取索引的内存 *** 作。
还有个小技巧,因为红色的RGB为定值,所以R为定值,那么只需要比较R和需要的R=237就行了,这是情况特殊可以如此优化,减少比较list这种相对较慢的 *** 作。
在python 3.9.6虚拟机中运行该脚本,花一秒切屏,让其自主 *** 作20秒自动结束。
平均得分大概在138-139(不同机器可能结果不同)
#include#include #include void click(int x, int y) { SetCursorPos(x,y); mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);//鼠标左键按下 mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);//鼠标左键抬起 } unsigned short getIndex() { // 返回横坐标 HDC hdc = GetDC(NULL); if (237 == GetRValue(GetPixel(hdc, 600, 725))) return 600; if (237 == GetRValue(GetPixel(hdc, 825, 725))) return 825; if (237 == GetRValue(GetPixel(hdc, 1080, 725))) return 1080; if (237 == GetRValue(GetPixel(hdc, 1325, 725))) return 1325; return 0; } int main() { Sleep(2000); for (;;) { click(getIndex()/1.5, 725/1.5); } return 0; }
通过c代码可以看出来,python版本就是利用ctypes调用了gdi32.dll等动态库的函数来通过系统API实现。那么C语言直接链接上,效果自然更好。
实现思路无变化,优化的思路也一样,只比较一个整形就够了,而且尽量数据大小小一点,比如这里short就够表示x坐标了使不上int这种32位的(虽然某种程度上,CPU的细节可能并不是这样思考的,也有可能int更快,但是样本太小了看不出来差别,就暂且这么强迫症地说着)
这个程序存在一个缺憾,就是它会无穷无尽地点击下去导致系统直接脱离控制,即使游戏结束。。。唯一的解决方案:alt+ctrl+delete然后注销,再登录,强制干掉这个进程。
click(getIndex()/1.5, 725/1.5);
这一行,经过测试必须除以一个1.5,不然特别奇怪。
测试的过程很简单,我们用c语言分别调用
click(0, 10)
click(10, 0)
click(10, 10)
click(10, 20)
令(x0, y0)= 上面每组数据的click的参数
然后检测(x, y):用pyautogui,就是不移动鼠标,通过键盘 *** 作,调到控制台,然后输出坐标,得到(x, y)
多取几组数据,然后将每组对应的x0和x;y0和y,前者放x轴,后者y轴,画出图像,猜出来是一个正比例函数,比例系数k=1.5
(大家根据自己的设备及分辨率调整比例系数,这个没法统一,但是网上全是直接带入坐标…)
各种手动优化(相对开始的代码,没贴出来)成这篇文章的版本后,加上-O3选项,预加载两次(也就是运行过这个程序,在系统不关闭的情况下,下次运行会更快,我也不知道为什么,但事实就是如此)
均分(20s)210
解释器的效率低下到不行,如果把游戏时间改到1000s之类的,差距会更明显。
分析得:c语言这个处理比python快52.17%
但是,值得考虑的是,这里频繁调用了Windows的api,所以并不能完全反应语言质量本身,虽然这个变量控制不变,但是实验中,绝不可能得到两种语言性能的绝对差距。
用数学知识易证,如果时间更长,两种语言的分数应该近似成正比例,但由于间隔越来越多,所以两者差值的导函数值越来越大。
综上所述:编译型语言效率远高于解释型语言,且效率差值随处理量成近似线性增长。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)