寫在前面node
17年年末Wechat出了這個跳一跳的小遊戲,今年2月份的時候簡單地玩了一下,發現被遊戲虐了(手太殘了只能跳20多)。c++
今天恰好有點空,因而就花了一個下午的時間寫了一個跳一跳的c++輔助。算法
因爲本OIER既不會Python,也不會安卓的USB調試,更不會單片機,故寫了一一個操做安卓模擬器的輔助。小程序
先放下效果:(只是先截個圖而已,截止至目前跳了2150次,運行1小時55分鐘)【未完待續】windows
據以前的跳一跳大賽的結果,儘管人類的第一爲1.2W分,但仍被本半天速成輔助輕鬆碾在地上。函數
--------------------------------------------------------------------------------我是分割線-----------------------------------------------------------------------------------------------oop
一些最基礎的東西測試
完成一次跳躍,你須要獲得棋子位置及方塊位置。進而計算出二者之間的距離,隨後跳躍相應的距離。優化
在我尚不瞭解跳一跳底層的數據的時候,抓屏分析幾乎是惟一選項。spa
因此你要先完成抓屏。
如何抓屏
在不額外導庫的狀況下,windows.h下提供了一個函數叫作getpixel,然而這個函數效率太低,顯然不合適如此大面積的圖像處理。
然而我又比較懶,不想去裝庫,但碰巧手頭有我半年前手寫的bmp庫。
我從網上找了個快捷鍵自動截屏的小程序,經過發送快捷鍵將屏幕數據轉爲bmp存入磁盤,再用bmp讀取(捂臉)。
反正這種簡單遊戲對輔助的吞吐量要求不高,就先這麼湊合着用吧....
代碼就不單獨拎出來了
完成抓屏後,爲了可以實現準確地識別棋子位置及方塊位置,咱們要先對界面作一些處理。
顯然,咱們要把背景和圖形陰影給過濾掉。
通過屢次抓屏分析,咱們獲得了跳一跳背景和陰影的一些特徵:
1,對於同行不一樣列,陰影部分的RGB數據徹底相同,背景部分的RGB數據也徹底相同,且陰影的RGB數據=背景的RGB數據/k (k約等於1.4356)
2,杜宇不一樣行的同列,背景部分的RGB數據可能不一樣,且對於所有行,$\Delta R,\ \Delta G,\ \Delta B≤50$。
咱們基於這兩個性質,對遊戲界面進行背景和陰影過濾。
如圖所示,過濾前與過濾後。(請先無視除背景顏色變化外的全部東西)
【實現方法】
咱們對於每一行分開處理,對於一個正在處理的行,找出該行內出現次數最多的顏色,隨後經過計算算出該行陰影的rgb數據。隨後將這兩種顏色的像素設爲黑色(#000000)
該方法的缺點也是顯而易見的,首先,沒法過濾陰影的邊框,且對於方塊分佈較密集的部分,該過濾方式可能會出現一些問題。
所幸的是,不過濾邊框幾乎不會影響到接下來的斷定,且目標點附近不會出現許多個方塊(僅1個嘛....)
濾色部分代碼:
1 for(int i=1;i<=P.n;i++){ 2 mp.clear();//該map用於判斷顏色衆數,因爲對吞吐量要求不高,故沒有進一步優化 3 for(int j=1;j<=P.m;j++) 4 mp[node(P.r[i][j],P.g[i][j],P.b[i][j])]++; 5 map<node,int>::iterator it; 6 node maxid,maxid2; int maxn=0; 7 for(it=mp.begin();it!=mp.end();it++){ 8 if(maxn<it->second){ 9 maxn=it->second; 10 maxid=it->first; 11 } 12 } 13 maxid2.r=maxid.r/conY;//cony即爲上文所說的某個常數 14 maxid2.g=maxid.g/conY; 15 maxid2.b=maxid.b/conY; 16 for(int j=1;j<=P.m;j++){ 17 if(maxid.cmp(P.r[i][j],P.g[i][j],P.b[i][j])) 18 P.r[i][j]=P.g[i][j]=P.b[i][j]=0; 19 if(maxid2.cmp(P.r[i][j],P.g[i][j],P.b[i][j])) 20 P.r[i][j]=P.g[i][j]=P.b[i][j]=0; 21 } 22 }
如何找到棋子
筆者經過簡單地分析,發現棋子的色域很是特殊,幾乎不存在與棋子相同顏色的方塊。
根據此特徵,咱們只須要求出在特定色域內的點所構成的點集,隨後對這些點求一個平均座標,再加上一個常數項的偏移,便可求出棋子的近似座標。
用於斷定點集的色域:$R∈[43,68],G∈[49,57],B∈[76,102]$。
捕捉到的棋子:
被染成灰色的部分爲在色域內的點,白色點即爲全部灰色點的平均加偏座標。
通過近萬次實際捕捉,能夠證實大膽猜測該方法是有效的。
代碼以下:
1 #define LR 43 2 #define RR 68 3 #define LG 49 4 #define RG 57 5 #define LB 76 6 #define RB 102 7 8 int sumx=0,sumy=0,cntx=0; 9 for(int i=1;i<=P.n;i++) 10 for(int j=1;j<=P.m;j++){ 11 int dR=abs(P.r[i][j]); 12 int dG=abs(P.g[i][j]); 13 int dB=abs(P.b[i][j]); 14 int cnt=0; 15 if(LR<=dR&&dR<=RR) cnt++; 16 if(LG<=dG&&dG<=RG) cnt++; 17 if(LB<=dB&&dB<=RB) cnt++; 18 if(cnt==3){ 19 P.r[i][j]=P.g[i][j]=P.b[i][j]=100; 20 sumx+=i; sumy+=j; cntx++; 21 } 22 }//識別棋子
如何肯定目標點
咱們先大膽假設,我上一次跳到了中心點!!!
咱們不難發現,在下個方塊的正中心,出現了大大的白點?
通過反覆的抓屏,咱們發現這個白點具備如下幾個性質:
1,永遠在目標的正中心。
2,除了邊界顏色與目標自己稍有混合外,其他部分相同且不變(#F1F1F1)
3,該點不變色部分的顏色具備近似惟一性(除了藥瓶瓶口附近外,其他的格子均不會出現這種顏色,包括看起來很白的幾個方塊)。
基於這三個特性,咱們不妨大膽猜出一個抓白點的方法:
在全屏範圍內搜索,是否存在一個色塊,知足其大小爲12*8px,且顏色均爲#F1F1F1。
經過屢次測試能夠發現知足此條件的色塊均在白點內,藥瓶子是找不到這樣的位子的。
在符合條件的色塊中,任意選出一個色塊,則目標點的座標即爲該色塊的中點(由於色塊數量很是少,且很是集中,經測試該方法偏移僅爲±2px,和因模擬器卡頓形成的偏移已相差無幾,故幾乎不用擔憂精度問題)。
因爲存在機器卡頓,偏差累計等問題,故沒法保證每次跳躍均落在中心點(目前中心率爲89.1%),目前最好的記錄是連續50次跳到中心點。
這個記錄,我相信不採用輔助人手是徹底沒法作到的。
代碼:
1 CAP.readfile("0000white.bmp");//對白點的特殊優化,因爲趕工,採用了直接讀取bmp的方法 2 int minn=1234567890,maxx=0,maxy=0; 3 for(int j=chessX;j>=chessX-300;j--) 4 for(int i=1;i<=P.m-CAP.m;i++){ 5 int sum=0,pcnt=0; 6 for(int ii=1;ii<CAP.m;ii++) 7 for(int jj=1;jj<CAP.n;jj++){ 8 sum+=pf(P.r[j+jj][i+ii]-CAP.r[jj][ii]); 9 sum+=pf(P.g[j+jj][i+ii]-CAP.g[jj][ii]); 10 sum+=pf(P.b[j+jj][i+ii]-CAP.b[jj][ii]); 11 } 12 if(sum==0){ 13 minn=sum,maxx=i,maxy=j; 14 break; 15 } 16 } 17 //cout<<minn<<endl; 18 if(minn==0){ 19 printf("catch white point!\n"); 20 for(int ii=1;ii<CAP.m;ii++) 21 for(int jj=1;jj<CAP.n;jj++){ 22 P.r[maxy+jj][maxx+ii]=0; 23 P.g[maxy+jj][maxx+ii]=255; 24 P.b[maxy+jj][maxx+ii]=0; 25 } 26 TX=maxy+6; TY=maxx+8; 27 P.r[TX][TY]=255; P.g[TX][TY]=P.b[TX][TY]=0; 28 // P.outfile("test.bmp"); 29 return 2; 30 }
綠色的位置即爲匹配到的白點,紅點爲預計落點
然而,不幸的是,仍是有11%的機率跳不到中心點上,下面咱們就要採用另外一套算法來解決問題:
咱們不妨假設這棋子在屏幕的左半邊,且咱們已知棋子的中心座標。
咱們以棋子爲原點,以正右方向爲X軸正半軸構造笛卡爾座標系。
經過簡單地統計,咱們不難發現目標的位置大概在$f(x)=tan \frac{\pi}{6}x$上
因而咱們構造五條射線$f(x)=tan \frac{\pi}{6}x-10$,$f(x)=tan \frac{\pi}{6}x-5$,$f(x)=tan \frac{\pi}{6}x$(圖中畫出了這一條),$f(x)=tan \frac{\pi}{6}x+5$,$f(x)=tan \frac{\pi}{6}x+10$,將在線上的全部像素取出。
隨後,咱們找出出現次數最多的顏色,對全部該顏色像素求一個平均座標,便可獲得目標點位置。
考慮到該遊戲中存在有花紋較多的方塊(如437天,木紋小板凳),咱們欽定一個常數eps(容許偏差範圍),求出像素數量最多的色域(能夠理解爲$R∈[r-eps,r+eps],G∈[g-eps,g+eps],B∈[b-eps,b+eps]$)求出該色域內全部像素的平均座標,獲得目標點。
如上方右圖所示,被染成綠色的點即爲斷定點,中心紅點即爲預計落點。
爲了提高精度,eps會根據出現的顏色數量而作出相應的調整。
本輔助中,設置了4個閾值5個eps。
對於棋子在屏幕右半邊的狀況同理。
代碼:
1 memset(X,0,sizeof(X)); memset(Y,0,sizeof(Y)); 2 memset(lineR,0,sizeof(lineR)); memset(lineG,0,sizeof(lineG)); memset(lineB,0,sizeof(lineB)); 3 //loop:; 4 mp.clear(); 5 if(chessY<=290 ){ 6 for(int i=chessY+60;i<=P.m;i++){//繪製函數 7 int j=chessX-(i-chessY)*tan30; 8 if(P.r[j][i]==0&&P.g[j][i]==0&&P.b[j][i]==0) continue; 9 cnt++; 10 lineR[cnt]=P.r[j][i]; 11 lineG[cnt]=P.g[j][i]; 12 lineB[cnt]=P.b[j][i]; 13 X[cnt]=j; Y[cnt]=i;//將函數上的點加入集合中,下文同理 14 mp[node(P.r[j][i],P.g[j][i],P.b[j][i])]++; 15 cnt++; 16 lineR[cnt]=P.r[j-4][i]; 17 lineG[cnt]=P.g[j-4][i]; 18 lineB[cnt]=P.b[j-4][i]; 19 X[cnt]=j-4; Y[cnt]=i; 20 mp[node(P.r[j-4][i],P.g[j-4][i],P.b[j-4][i])]++; 21 cnt++; 22 lineR[cnt]=P.r[j+4][i]; 23 lineG[cnt]=P.g[j+4][i]; 24 lineB[cnt]=P.b[j+4][i]; 25 X[cnt]=j+4; Y[cnt]=i; 26 mp[node(P.r[j+4][i],P.g[j+4][i],P.b[j+4][i])]++; 27 cnt++; 28 lineR[cnt]=P.r[j+8][i]; 29 lineG[cnt]=P.g[j+8][i]; 30 lineB[cnt]=P.b[j+8][i]; 31 X[cnt]=j+8; Y[cnt]=i; 32 mp[node(P.r[j+8][i],P.g[j+8][i],P.b[j+8][i])]++; 33 cnt++; 34 lineR[cnt]=P.r[j-8][i]; 35 lineG[cnt]=P.g[j-8][i]; 36 lineB[cnt]=P.b[j-8][i]; 37 X[cnt]=j-8; Y[cnt]=i; 38 mp[node(P.r[j-8][i],P.g[j-8][i],P.b[j-8][i])]++; 39 P.r[j+1][i]=P.r[j-1][i]=255; 40 P.g[j+1][i]=P.g[j-1][i]=255; 41 P.b[j+1][i]=P.b[j-1][i]=0; 42 } 43 }else{ 44 for(int i=chessY-60;i;i--){ 45 int j=chessX-(chessY-i)*tan30; 46 if(P.r[j][i]==0&&P.g[j][i]==0&&P.b[j][i]==0) continue; 47 cnt++; 48 lineR[cnt]=P.r[j][i]; 49 lineG[cnt]=P.g[j][i]; 50 lineB[cnt]=P.b[j][i]; 51 X[cnt]=j; Y[cnt]=i; 52 mp[node(P.r[j][i],P.g[j][i],P.b[j][i])]++; 53 cnt++; 54 lineR[cnt]=P.r[j-4][i]; 55 lineG[cnt]=P.g[j-4][i]; 56 lineB[cnt]=P.b[j-4][i]; 57 X[cnt]=j-4; Y[cnt]=i; 58 mp[node(P.r[j-4][i],P.g[j-4][i],P.b[j-4][i])]++; 59 cnt++; 60 lineR[cnt]=P.r[j+4][i]; 61 lineG[cnt]=P.g[j+4][i]; 62 lineB[cnt]=P.b[j+4][i]; 63 X[cnt]=j+4; Y[cnt]=i; 64 cnt++; 65 mp[node(P.r[j+4][i],P.g[j+4][i],P.b[j+4][i])]++; 66 lineR[cnt]=P.r[j+8][i]; 67 lineG[cnt]=P.g[j+8][i]; 68 lineB[cnt]=P.b[j+8][i]; 69 X[cnt]=j+8; Y[cnt]=i; 70 cnt++; 71 mp[node(P.r[j+8][i],P.g[j+8][i],P.b[j+8][i])]++; 72 lineR[cnt]=P.r[j-8][i]; 73 lineG[cnt]=P.g[j-8][i]; 74 lineB[cnt]=P.b[j-8][i]; 75 X[cnt]=j-8; Y[cnt]=i; 76 mp[node(P.r[j-8][i],P.g[j-8][i],P.b[j-8][i])]++; 77 P.r[j+1][i]=P.r[j-1][i]=255; 78 P.g[j+1][i]=P.g[j-1][i]=255; 79 P.b[j+1][i]=P.b[j-1][i]=0; 80 } 81 } 82 //printf("colorsum:%d\n",mp.size()); 83 if(mp.size()<40){ 84 JumpepsR=JumpepsG=JumpepsB=1; 85 }else if(mp.size()<100){ 86 JumpepsR=JumpepsG=JumpepsB=4; 87 }else if(mp.size()<400){ 88 JumpepsR=JumpepsG=JumpepsB=7; 89 }else JumpepsR=JumpepsG=JumpepsB=10; 90 if(cnt==0) 91 return 1; 92 //if(cnt==0) goto loop; 93 int maxn=0,maxid=0,quan=3; 94 for(int i=1;i<=cnt;i++){ 95 quan=3; 96 int R=lineR[i]; 97 int G=lineG[i]; 98 int B=lineB[i]; 99 int sum=0; 100 for(int j=1;j<=cnt;j++){ 101 int DeltaR=abs(lineR[j]-R); 102 int DeltaG=abs(lineG[j]-G); 103 int DeltaB=abs(lineB[j]-B); 104 if(DeltaR>JumpepsR) continue; 105 if(DeltaG>JumpepsG) continue; 106 if(DeltaB>JumpepsB) continue; 107 sum+=abs(X[j]-chessX)*0.05+4; //求出最大的色域 108 } 109 if(sum>maxn) maxn=sum,maxid=i; 110 } 111 int sumX=0,sumY=0,sum=0; 112 int R=lineR[maxid]; 113 int G=lineG[maxid]; 114 int B=lineB[maxid]; 115 for(int j=1;j<=cnt;j++){ 116 int DeltaR=abs(lineR[j]-R); 117 int DeltaG=abs(lineG[j]-G); 118 int DeltaB=abs(lineB[j]-B); 119 if(DeltaR>JumpepsR) continue; 120 if(DeltaG>JumpepsG) continue; 121 if(DeltaB>JumpepsB) continue; 122 sum++; 123 P.r[X[j]][Y[j]]=0; 124 P.g[X[j]][Y[j]]=255; 125 P.b[X[j]][Y[j]]=0; 126 sumX+=X[j]; sumY+=Y[j];//求出該色域內點出現的最大次數 127 } 128 if(sum==0) 129 return 1; 130 sumX/=sum; sumY/=sum;//求出座標 131 //求出目標點座標 132 P.r[sumX][sumY]=255; P.g[sumX][sumY]=P.b[sumX][sumY]=0; 133 TX=sumX; TY=sumY;
找到座標後,如何肯定按壓的時長
咱們不妨猜測這個按壓時間與兩點間距呈線性關係。
經過簡單地採樣+散點圖,因而就擬合出了該直線的斜率。
經過該方法,獲得的跳躍時間$T=2.55 \times dist$,其中$dist$表示起點到終點的距離,單位爲像素,T的單位爲毫秒。
後來,我發現該擬合方法偏差較大,只能實現連續36次跳至中心點,中心點率爲85%。
爲了進一步提升精度,我又發現了一個性質:須要跳躍的時間與dist並沒有直接關聯,但與dist在$y=tan \frac {\pi}{6}x$上的投影有關。
所以,優化算法以下:
令向量$\vec a=BEGIN-END$,其中BEGIN表示棋子中心點座標,END表示目標點座標。
設一個單位向量$\vec b=(cos \frac{\pi}{6},sin \frac{\pi}{6})$
則跳躍時間$T=2.53 \times \vec a \cdot \vec b$ ,單位仍爲毫秒。
再簡單地調下參,就能夠實現90%的中心點率,最高連續50次中心點啦~。
剛剛跳到4.4W掛掉了....本蒟蒻修復完bug了...
若要看二代輔助的細節,請移步下篇
整個一代輔助代碼以下:
#include<bits/stdc++.h> #include<cmath> #include<windows.h> #define d(x) keybd_event(x,0,0,0) #define u(x) keybd_event(x,0,2,0) #define s(x) Sleep(x) #define me(x) mouse_event(x,0,0,0,0) #define sc(x,y) SetCursorPos(x,y) #define gk(x) GetAsyncKeyState(x) #define M 100000 using namespace std; int up(int x){while((x*3)%4!=0) x++;return x;} int lf(int x){return abs(x);} void printhead(unsigned char c[],int n,int m){ //該函數用於寫入一個24位bmp頭 c[0]=0x42; c[1]=0x4d; //BM unsigned siz=54+3*up(n)*up(m); for(int i=2;i<=5;i++){ c[i]=siz&255; siz=siz>>8; }//寫入siz siz=3*n*m; c[10]=0x36;//寫入數據頭位置 c[0x0e]=0x28;//頭大小 for(int i=0x12;i<=0x15;i++) c[i]=m&255,m>>=8;//寫入寬度 for(int i=0x16;i<=0x19;i++) c[i]=n&255,n>>=8;//寫入高度 c[0x1a]=1;//永遠爲1 c[0x1c]=0x18;//24位位圖 //for(int i=0x22;i<=0x25;i++) c[i]=siz&255,siz>>=8;//寫入去頭字節數 } #define MFLONG 15000000 #define W 1921 #define H 1081 unsigned char _c[MFLONG]={0}; struct board{//畫布函數 int n,m;//寬高 unsigned char r[H][W],g[H][W],b[H][W]; board(){ n=m=0; memset(b,0,sizeof(b)); memset(r,0,sizeof(r)); memset(g,0,sizeof(g)); } board(int nn,int mm,int R,int G,int B){ n=nn; m=mm; memset(b,B,sizeof(b)); memset(r,R,sizeof(r)); memset(g,G,sizeof(g)); } void clear(){ n=m=0; memset(b,0,sizeof(b)); memset(r,0,sizeof(r)); memset(g,0,sizeof(g)); } void outfile(char ad[]){ FILE *fp; fp=fopen(ad,"wb"); printhead(_c,n,m); int ns=54; for(int i=n;i;i--){ for(int j=1;j<=m;j++){ _c[ns++]=b[i][j]; _c[ns++]=g[i][j]; _c[ns++]=r[i][j]; } int k=(3*m)%4; for(int i=0;i<k;i++) _c[ns++]=0; } fwrite(_c,1,ns,fp); fclose(fp); } void readfile(char ad[]){ FILE *fp; fp=fopen(ad,"rb"); fread(_c,1,MFLONG,fp); fclose(fp); for(int i=0x15;i>=0x12;i--) m=m<<8,m=m+_c[i]; for(int i=0x19;i>=0x16;i--) n=n<<8,n=n+_c[i]; int ns=54; for(int i=n;i;i--){ for(int j=1;j<=m;j++){ b[i][j]=_c[ns++]; g[i][j]=_c[ns++]; r[i][j]=_c[ns++]; } int k=(m*3)%4; ns+=k; } fclose(fp); } }; board S,P,P2,CAP; void capture(){ d(VK_SNAPSHOT); u(VK_SNAPSHOT); S.readfile("screenx.bmp"); } #define epsR 2 #define epsG 2 #define epsB 2 #define conY 1.4356 ///過濾底色和陰影的參數 #define LR 43 #define RR 68 #define LG 49 #define RG 57 #define LB 76 #define RB 102 #define tan30 0.5773 /*#define JumpepsR 7 #define JumpepsG 7 #define JumpepsB 7//用於判斷目標點的東西*/ int JumpepsR,JumpepsG,JumpepsB; int wx[]={-1,-1,-1,0,1,1,1,0}; int wy[]={-1,0,1,1,1,0,-1,-1}; struct node{ int r,g,b; node(){r=g=b=0;} node(unsigned char R,unsigned char G,unsigned B){ r=R; g=G; b=B; } friend bool operator <(node a,node b){ if(a.r!=b.r) return a.r<b.r; if(a.g!=b.g) return a.g<b.g; return a.b<b.b; } bool cmp(int R,int G,int B){ int e1=abs(r-R); int e2=abs(g-G); int e3=abs(b-B); if(e1>epsR) return 0; if(e2>epsG) return 0; if(e3>epsB) return 0; return 1; } }; int pf(int x){return x*x;} map<node,int> mp,mmp; int chessX,chessY;//棋子的x,y座標 int TX,TY; int lineR[10000]={0},lineG[10000]={0},lineB[10000]={0},X[10000]={0},Y[10000]={0}; int wave(){//完成對圖像的底色和陰影過濾,以及求出棋子的中心點 P.clear(); int sx=32,ex=1074; int sy=682,ey=1265; P.m=ey-sy+1; P.n=ex-sx+1; for(int i=sx;i<=ex;i++) for(int j=sy;j<=ey;j++){ P.r[i-sx+1][j-sy+1]=S.r[i][j]; P.g[i-sx+1][j-sy+1]=S.g[i][j]; P.b[i-sx+1][j-sy+1]=S.b[i][j]; } // P.readfile("st720.bmp"); //抓出圖像 P2=P; int sumx=0,sumy=0,cntx=0; for(int i=1;i<=P.n;i++) for(int j=1;j<=P.m;j++){ int dR=abs(P.r[i][j]); int dG=abs(P.g[i][j]); int dB=abs(P.b[i][j]); int cnt=0; if(LR<=dR&&dR<=RR) cnt++; if(LG<=dG&&dG<=RG) cnt++; if(LB<=dB&&dB<=RB) cnt++; if(cnt==3){ P.r[i][j]=P.g[i][j]=P.b[i][j]=100; sumx+=i; sumy+=j; cntx++; } }//識別棋子 for(int i=1;i<=P.n;i++){ mp.clear(); for(int j=1;j<=P.m;j++) mp[node(P.r[i][j],P.g[i][j],P.b[i][j])]++; map<node,int>::iterator it; node maxid,maxid2; int maxn=0; for(it=mp.begin();it!=mp.end();it++){ if(maxn<it->second){ maxn=it->second; maxid=it->first; } } maxid2.r=maxid.r/conY; maxid2.g=maxid.g/conY; maxid2.b=maxid.b/conY; for(int j=1;j<=P.m;j++){ if(maxid.cmp(P.r[i][j],P.g[i][j],P.b[i][j])) P.r[i][j]=P.g[i][j]=P.b[i][j]=0; if(maxid2.cmp(P.r[i][j],P.g[i][j],P.b[i][j])) P.r[i][j]=P.g[i][j]=P.b[i][j]=0; } } if(cntx==0) return 1; sumx/=cntx; sumy/=cntx; sumx+=14; P.r[sumx][sumy]=P.g[sumx][sumy]=P.b[sumx][sumy]=255; chessX=sumx+2; chessY=sumy; int cnt=0; // P.outfile("ok.bmp"); CAP.readfile("0000white.bmp");//對白點的特殊優化 int minn=1234567890,maxx=0,maxy=0; for(int j=chessX;j>=chessX-300;j--) for(int i=1;i<=P.m-CAP.m;i++){ int sum=0,pcnt=0; for(int ii=1;ii<CAP.m;ii++) for(int jj=1;jj<CAP.n;jj++){ sum+=pf(P.r[j+jj][i+ii]-CAP.r[jj][ii]); sum+=pf(P.g[j+jj][i+ii]-CAP.g[jj][ii]); sum+=pf(P.b[j+jj][i+ii]-CAP.b[jj][ii]); } if(sum==0){ minn=sum,maxx=i,maxy=j; break; } } //cout<<minn<<endl; if(minn==0){ printf("catch white point!\n"); for(int ii=1;ii<CAP.m;ii++) for(int jj=1;jj<CAP.n;jj++){ P.r[maxy+jj][maxx+ii]=0; P.g[maxy+jj][maxx+ii]=255; P.b[maxy+jj][maxx+ii]=0; } TX=maxy+6; TY=maxx+8; P.r[TX][TY]=255; P.g[TX][TY]=P.b[TX][TY]=0; // P.outfile("test.bmp"); return 2; } CAP.readfile("0000brown.bmp");//對437天的特殊優化 minn=1234567890,maxx=0,maxy=0; for(int j=chessX;j>=chessX-300;j--) for(int i=1;i<=P.m-CAP.m;i++){ int sum=0,pcnt=0; for(int ii=1;ii<CAP.m;ii++) for(int jj=1;jj<CAP.n;jj++){ sum+=pf(P.r[j+jj][i+ii]-CAP.r[jj][ii]); sum+=pf(P.g[j+jj][i+ii]-CAP.g[jj][ii]); sum+=pf(P.b[j+jj][i+ii]-CAP.b[jj][ii]); } if(sum==0){ minn=sum,maxx=i,maxy=j; break; } } //cout<<minn<<endl; if(minn==0){ printf("catch brown point!\n"); for(int ii=1;ii<CAP.m;ii++) for(int jj=1;jj<CAP.n;jj++){ P.r[maxy+jj][maxx+ii]=0; P.g[maxy+jj][maxx+ii]=255; P.b[maxy+jj][maxx+ii]=0; } TX=maxy+4; TY=maxx+6; P.r[TX][TY]=255; P.g[TX][TY]=P.b[TX][TY]=0; // P.outfile("test.bmp"); return 0; } //printf("%d %d\n",maxx,maxy); memset(X,0,sizeof(X)); memset(Y,0,sizeof(Y)); memset(lineR,0,sizeof(lineR)); memset(lineG,0,sizeof(lineG)); memset(lineB,0,sizeof(lineB)); //loop:; mp.clear(); if(chessY<=290 ){ for(int i=chessY+60;i<=P.m;i++){ int j=chessX-(i-chessY)*tan30; if(P.r[j][i]==0&&P.g[j][i]==0&&P.b[j][i]==0) continue; cnt++; lineR[cnt]=P.r[j][i]; lineG[cnt]=P.g[j][i]; lineB[cnt]=P.b[j][i]; X[cnt]=j; Y[cnt]=i; mp[node(P.r[j][i],P.g[j][i],P.b[j][i])]++; cnt++; lineR[cnt]=P.r[j-4][i]; lineG[cnt]=P.g[j-4][i]; lineB[cnt]=P.b[j-4][i]; X[cnt]=j-4; Y[cnt]=i; mp[node(P.r[j-4][i],P.g[j-4][i],P.b[j-4][i])]++; cnt++; lineR[cnt]=P.r[j+4][i]; lineG[cnt]=P.g[j+4][i]; lineB[cnt]=P.b[j+4][i]; X[cnt]=j+4; Y[cnt]=i; mp[node(P.r[j+4][i],P.g[j+4][i],P.b[j+4][i])]++; cnt++; lineR[cnt]=P.r[j+8][i]; lineG[cnt]=P.g[j+8][i]; lineB[cnt]=P.b[j+8][i]; X[cnt]=j+8; Y[cnt]=i; mp[node(P.r[j+8][i],P.g[j+8][i],P.b[j+8][i])]++; cnt++; lineR[cnt]=P.r[j-8][i]; lineG[cnt]=P.g[j-8][i]; lineB[cnt]=P.b[j-8][i]; X[cnt]=j-8; Y[cnt]=i; mp[node(P.r[j-8][i],P.g[j-8][i],P.b[j-8][i])]++; P.r[j+1][i]=P.r[j-1][i]=255; P.g[j+1][i]=P.g[j-1][i]=255; P.b[j+1][i]=P.b[j-1][i]=0; } }else{ for(int i=chessY-60;i;i--){ int j=chessX-(chessY-i)*tan30; if(P.r[j][i]==0&&P.g[j][i]==0&&P.b[j][i]==0) continue; cnt++; lineR[cnt]=P.r[j][i]; lineG[cnt]=P.g[j][i]; lineB[cnt]=P.b[j][i]; X[cnt]=j; Y[cnt]=i; mp[node(P.r[j][i],P.g[j][i],P.b[j][i])]++; cnt++; lineR[cnt]=P.r[j-4][i]; lineG[cnt]=P.g[j-4][i]; lineB[cnt]=P.b[j-4][i]; X[cnt]=j-4; Y[cnt]=i; mp[node(P.r[j-4][i],P.g[j-4][i],P.b[j-4][i])]++; cnt++; lineR[cnt]=P.r[j+4][i]; lineG[cnt]=P.g[j+4][i]; lineB[cnt]=P.b[j+4][i]; X[cnt]=j+4; Y[cnt]=i; cnt++; mp[node(P.r[j+4][i],P.g[j+4][i],P.b[j+4][i])]++; lineR[cnt]=P.r[j+8][i]; lineG[cnt]=P.g[j+8][i]; lineB[cnt]=P.b[j+8][i]; X[cnt]=j+8; Y[cnt]=i; cnt++; mp[node(P.r[j+8][i],P.g[j+8][i],P.b[j+8][i])]++; lineR[cnt]=P.r[j-8][i]; lineG[cnt]=P.g[j-8][i]; lineB[cnt]=P.b[j-8][i]; X[cnt]=j-8; Y[cnt]=i; mp[node(P.r[j-8][i],P.g[j-8][i],P.b[j-8][i])]++; P.r[j+1][i]=P.r[j-1][i]=255; P.g[j+1][i]=P.g[j-1][i]=255; P.b[j+1][i]=P.b[j-1][i]=0; } } //printf("colorsum:%d\n",mp.size()); if(mp.size()<40){ JumpepsR=JumpepsG=JumpepsB=1; }else if(mp.size()<100){ JumpepsR=JumpepsG=JumpepsB=4; }else if(mp.size()<400){ JumpepsR=JumpepsG=JumpepsB=7; }else JumpepsR=JumpepsG=JumpepsB=10; if(cnt==0) return 1; //if(cnt==0) goto loop; int maxn=0,maxid=0,quan=3; for(int i=1;i<=cnt;i++){ quan=3; int R=lineR[i]; int G=lineG[i]; int B=lineB[i]; int sum=0; for(int j=1;j<=cnt;j++){ int DeltaR=abs(lineR[j]-R); int DeltaG=abs(lineG[j]-G); int DeltaB=abs(lineB[j]-B); if(DeltaR>JumpepsR) continue; if(DeltaG>JumpepsG) continue; if(DeltaB>JumpepsB) continue; sum+=abs(X[j]-chessX)*0.05+4; } if(sum>maxn) maxn=sum,maxid=i; } int sumX=0,sumY=0,sum=0; int R=lineR[maxid]; int G=lineG[maxid]; int B=lineB[maxid]; for(int j=1;j<=cnt;j++){ int DeltaR=abs(lineR[j]-R); int DeltaG=abs(lineG[j]-G); int DeltaB=abs(lineB[j]-B); if(DeltaR>JumpepsR) continue; if(DeltaG>JumpepsG) continue; if(DeltaB>JumpepsB) continue; sum++; P.r[X[j]][Y[j]]=0; P.g[X[j]][Y[j]]=255; P.b[X[j]][Y[j]]=0; sumX+=X[j]; sumY+=Y[j]; } if(sum==0) return 1; sumX/=sum; sumY/=sum; //求出目標點座標 P.r[sumX][sumY]=255; P.g[sumX][sumY]=P.b[sumX][sumY]=0; TX=sumX; TY=sumY; //P.outfile("test.bmp"); return 0; //點擊模組 } int main(){ while(!gk(VK_F7)) s(10); keybd_event(VK_F7,0,2,0); char c[100]; int cas=0,x=0,y,sum=0,buchang=0; //Sleep(2000); int last=0; while(1){ cas++; capture(); Sleep(400); capture(); Sleep(200); int k=wave(); if(gk(VK_F7)) return 0; int X=abs(TX-chessX),Y=abs(TY-chessY); double d=0.866,b=1.732; int he=2*X+d*(Y-b*X); printf("dist=%d pixel\n",he); me(2); s(he*2.528); me(4); Sleep(1500); freopen("log.txt","r",stdin); scanf("%d%d",&x,&y); fclose(stdin); sprintf(c,"log%d.bmp",x); P.outfile(c); sprintf(c,"st%d.bmp",x); P2.outfile(c); x++; y+=(k==2); printf("sumjump=%d,centrejump=%d\n\n",x,y); freopen("log.txt","w",stdout); printf("%d %d\n",x,y); fclose(stdout); freopen("con","w",stdout); } }