寫在前面
17年年底Wechat出了這個跳一跳的小游戲,今年2月份的時候簡單地玩了一下,發現被游戲虐了(手太殘了只能跳20多)。
今天剛好有點空,於是就花了一個下午的時間寫了一個跳一跳的c++輔助。
由於本OIER既不會Python,也不會安卓的USB調試,更不會單片機,故寫了一一個操作安卓模擬器的輔助。
先放下效果:(只是先截個圖而已,截止至目前跳了2150次,運行1小時55分鍾)【未完待續】
據之前的跳一跳大賽的結果,盡管人類的第一為1.2W分,但仍被本半天速成輔助輕松碾在地上。
--------------------------------------------------------------------------------我是分割線-----------------------------------------------------------------------------------------------
一些最基礎的東西
完成一次跳躍,你需要得到棋子位置及方塊位置。進而計算出兩者之間的距離,隨后跳躍相應的距離。
在我尚不了解跳一跳底層的數據的時候,抓屏分析幾乎是唯一選項。
所以你要先完成抓屏。
如何抓屏
在不額外導庫的情況下,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); } }