版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第5講 綜合應用自動掃雷器,知識點,一、Windows掃雷游戲程序 二、兩個參考程序 三、自動掃雷器的原理 四、程序界面采用的技術和方法 4.1 獲取并顯示操作系統(tǒng)的版本號 4.2 啟動掃雷游戲 4.3 并排居中顯示兩個窗口、計算掃雷游戲地圖行數(shù)和列數(shù) 4.4 開啟新局 五、決策前的準備 5.1 掃描地圖 5.2 方格16種狀態(tài)的表示 5.3 獲取每個方格第8行16個像素的顏色并與預存的16種狀態(tài)比對 六、決策 6.1 普通決策 6.2 高級決策,一、Windows掃雷游戲程序,鼠標左右鍵的作用: 鼠標左鍵單擊:點開某個位置; 鼠標右鍵單擊:將某個位置標記為地雷; 鼠標左右鍵同時單擊:見下一頁
2、。 在自動掃雷程序中,需要人為地向掃雷程序發(fā)送這些鼠標消息,達到自動標記地雷或點開位置的功能,鼠標左右鍵同時單擊:如果單擊的位置周圍8個相鄰位置中已標記為地雷的個數(shù) = 該位置顯示的數(shù)字,則將其他未點開的位置全部點開(如果標記的位置是正確的,則其他位置中不可能有地雷)。 思考:鼠標左右鍵同時單擊下圖中標注的位置,會有什么效果,思考,人在玩掃雷游戲時,會采用哪些推理規(guī)則,期末作品參考,模仿Windows掃雷游戲,用VC/MFC設計一個掃雷游戲,其界面和功能可參考Windows掃雷游戲,二、兩個參考程序,軟件名稱:自動掃雷器: 作者:任全。 開發(fā)工具:VC/MFC。 特點:需要人工點開,當算法不能
3、繼續(xù)時,需要人工介入。 說明:該程序為本課件的參考程序,本課件做了簡化、并補充了大量的注釋,軟件名稱:自動掃雷。 作者:葛永。 開發(fā)工具:未知。 特點:以猜測替代人工操作。功能更全面,提供了多個選項的設置,甚至可以自定義推理規(guī)則,三、自動掃雷器的原理,啟動掃雷游戲后,當用戶點擊“掃雷”按鈕時,掃描掃雷游戲地圖,通過提取每個方格(1616)中間第8行16個像素的顏色,跟預存的16種狀態(tài)的顏色進行比對,從而判斷每個方格的狀態(tài),根據(jù)每個方格狀態(tài)的信息進行決策(包括普通決策和高級決策),從而點開某個(或某些)位置,或者將某個(或某些)位置標記為地雷。 某次決策后: 如果判定出現(xiàn)了踩到地雷的狀態(tài),則提示
4、“掃雷失敗”。 如果所有地雷位置都正確標記出來、其他位置都點開了,則提示“掃雷成功”。 如果某次決策無法點開位置或標記地雷,則提示“算法不能繼續(xù)了”,請求用戶手動點開一些位置,決策例子: 請試著根據(jù)下圖所顯示的各方格的狀態(tài)判斷哪些位置可以標記為地雷,哪些位置可以點開,補充:Windows畫圖應用程序妙用,將一個bmp位圖文件用畫圖軟件打開,然后放大8倍,可以清晰地觀察到每個像素。 可以顯示網(wǎng)格,可以顯示縮略圖。 在狀態(tài)欄中可以顯示當前鼠標光標的位置,所選矩形區(qū)域的大小等,畫圖程序在分析自動掃雷器代碼中的作用: 掃雷游戲程序和自動掃雷器窗口大小分別是多少個像素,標題欄和菜單欄高度是多少個像素,邊
5、框高度或寬度是多少個像素,等等。 每個方格1616區(qū)域具體包含了哪些像素。 提取每個方格第8行16個像素的顏色,第8行具體是哪一行。等等,補充:其他工具軟件的應用,01 取屏幕上任一點的RGB顏色值(綠色) :色值傳遞員(plsread)。 02 中英文顏色RGB代碼對照表(綠色)。 03 YUV、RGB轉換并帶顏色顯示(綠色)。 04 RGB顏色分析器V40(綠色)。 以上軟件均已上傳到網(wǎng)絡課堂(或服務器)中,補充:像素,位圖文件是由像素組成。行和列上的像素序號從0開始計起。 在Windows繪圖應用程序中打開一幅位圖文件(*.bmp),然后放大8倍,并顯示網(wǎng)格,可以清晰地觀察到位圖的每個像
6、素。 顯示器屏幕分辨率為1280800,則意味著水平方向上為1280個像素,豎直方向上為800個像素。 許多GDI繪圖函數(shù)的繪圖單位也是像素,補充:坐標系,屏幕坐標系:坐標系原點在屏幕左上角。 客戶區(qū)坐標系:坐標系原點在客戶區(qū)左上角。 坐標系轉換函數(shù): API函數(shù):ClientToScreen,x,x,y,y,掃雷游戲窗口中某一個點的客戶區(qū)坐標為(20,20),其屏幕坐標可能為(277,282,補充:屏幕坐標和區(qū)域,屏幕坐標:CPoint類(MFC中的類) 表示屏幕上一個點的坐標。 與Windows中的結構體POINT(即API中的結構體)類似,增加了很多成員函數(shù)。 區(qū)域:CRect(MFC中
7、的類) 表示屏幕上一個矩形區(qū)域。 與Windows中的結構體RECT(即API中的結構體)類似,增加了很多成員函數(shù),typedef struct tagPOINT LONG x; LONG y; POINT,typedef struct tagRECT LONG left; LONG top; LONG right; LONG bottom; RECT,補充:MFC/SDK的數(shù)據(jù)類型與C/C+的數(shù)據(jù)類型,MFC,Microsoft Foundation Class Library。 SDK,Windows Software Development Kit。在SDK應用程序中,采用API函數(shù)來實
8、現(xiàn)程序功能。所以SDK應用程序也就是基于API函數(shù)的應用程序。 在MFC/SDK中定義了很多數(shù)據(jù)類型,為了跟其他計算機語言中的數(shù)據(jù)類型相區(qū)別,特意采用大寫字母。 BOOL、BSTR、BYTE、COLORREF、DWORD、LONG、LPARAM、LPCSTR、LPSTR、LPCTSTR、LPTSTR、LPVOID、LRESULT、UINT、WNDPROC、WORD、WPARAM、POSITION、LPCRECT等等。 每種數(shù)據(jù)類型的含義及所占字節(jié)數(shù)請查閱MSDN。 在MFC/SDK中仍然支持C/C+的數(shù)據(jù)類型,補充:顏色在計算機中的表示,在計算機中,顏色是用R(紅)、G(綠)、B(藍)3個分量
9、來表示的,每個分量取值為0255,可以用一個字節(jié)來存儲。因此,RGB一共可以表示255255255種顏色。 在Windows操作系統(tǒng)中,使用COLORREF數(shù)據(jù)類型來表示RGB顏色。COLORREF占4個字節(jié)、32位,用16進制來表示是0 x00bbggrr,即最高字節(jié)不用,次高字節(jié)表示B分量、次低字節(jié)表示G分量,最低字節(jié)表示R分量。 在有的時候(比如在調試狀態(tài)下),COLORREF是以十進制形式顯示的,比如白色(0 x00FFFFFF)的值為16777215。 API函數(shù)GetPixel可以獲得屏幕上指定位置的顏色值,返回的是COLORREF類型的值,常用顏色列表: RGB值COLORREF
10、顏色中文名稱 RGB( 0, 0, 0)0 x00000000黑色 RGB(128, 0, 0)0 x00000080栗色 RGB( 0, 128, 0)0 x00008000深綠色 RGB(128, 128, 0)0 x00008080橄欖色 RGB( 0, 0, 128)0 x00800000海軍藍色 RGB(128, 0, 128)0 x00800080紫色 RGB( 0, 128, 128)0 x00808000水鴨色 RGB(128,128,128)0 x00808080灰色 RGB(192,192,192)0 x00C0C0C0銀白色 RGB(255, 0, 0)0 x000000
11、FF紅色 RGB( 0, 255, 0)0 x0000FF00綠色 RGB(255, 255, 0)0 x0000FFFF黃色 RGB( 0, 0, 255)0 x00FF0000藍色 RGB(255, 0, 255)0 x00FF00FF洋紅色 RGB( 0, 255, 255)0 x00FFFF00青色 RGB(255,255,255)0 x00FFFFFF白色 注意,在COLORREF數(shù)據(jù)中,是按BGR的順序從高位到低位存放的。 這16種顏色也是掃雷程序各方格中可能出現(xiàn)的16種顏色,四、程序界面采用的技術和方法,自動掃雷器界面: 基于對話框的應用程序。 界面很簡單,CMineCrackD
12、lg類自定義數(shù)據(jù)成員和函數(shù)成員含義及功能。 數(shù)據(jù)成員,BOOL m_bWin98;/操作系統(tǒng)是否為Win98、Win2003的標志變量 CStringwinMineClassName;/掃雷游戲程序窗口類名 HWND hWinMineWnd;/掃雷游戲窗口句柄 CRect rectWinMine;/掃雷游戲窗口區(qū)域 CRect rectMe;/本程序窗口區(qū)域 BOOL m_bStart;/掃雷游戲是否啟動的標志 int m_nWidth;/掃雷游戲水平方向上方格的數(shù)目(即列數(shù)),高級是16行30列 int m_nHeight;/掃雷游戲豎直方向上方格的數(shù)目(即行數(shù)) int m_nMineNu
13、m;/地雷的個數(shù) int m_nMineCurNum;/當前已標記出的地雷數(shù)目 /申請m_nWidthm_nHeight大小的存儲空間 /每個元素代表一個位置,取值為0FF,分別代表一種狀態(tài) BYTE *m_map; BYTE m_ColorSample168;/預先存儲的掃雷游戲方格16種狀態(tài)的顏色,4.0 數(shù)據(jù)成員和函數(shù)成員說明,數(shù)據(jù)成員m_bWin98說明: Win98、Win2003和Win2000、WinXP中的掃雷應用窗口有一些細微差別:Win98、Win2003中的掃雷程序窗口寬度多4個像素、高度多4個像素。 在通過窗口大小來計算掃雷游戲的行數(shù)和列數(shù)時要區(qū)分Win98、Win20
14、03系統(tǒng)和其他系統(tǒng),BOOL m_bWin98; CStringwinMineClassName; HWND hWinMineWnd; CRect rectWinMine; CRect rectMe; BOOL m_bStart; int m_nWidth; int m_nHeight; int m_nMineNum; int m_nMineCurNum; BYTE *m_map; BYTE m_ColorSample168,數(shù)據(jù)成員m_nWidth、m_nHeight說明: m_nWidth:掃雷游戲水平方向上有多少個方格。 m_nHeight:掃雷游戲豎直方向上有多少個方格。 數(shù)數(shù)高級模式
15、水平和豎直方向上分別有多少個方格,BOOL m_bWin98; CStringwinMineClassName; HWND hWinMineWnd; CRect rectWinMine; CRect rectMe; BOOL m_bStart; int m_nWidth; int m_nHeight; int m_nMineNum; int m_nMineCurNum; BYTE *m_map; BYTE m_ColorSample168,BOOL m_bWin98; CStringwinMineClassName; HWND hWinMineWnd; CRect rectWinMine; C
16、Rect rectMe; BOOL m_bStart; int m_nWidth; int m_nHeight; int m_nMineNum; int m_nMineCurNum; BYTE *m_map; BYTE m_ColorSample168,數(shù)據(jù)成員m_map數(shù)組說明: 在啟動(含重新開具)掃雷游戲時,申請一維數(shù)組存儲空間,并用m_map指向這段存儲空間。 一維數(shù)組存儲空間當作二維數(shù)組存儲空間使用。 m_map數(shù)組元素取值含義,define UNKNOW0 x00/未知 #define NOMINE0 xFF/確定沒有地雷 #define ISMINE0 x0F/確定為地雷 #de
17、fine NEIGHBOR_10 x01/數(shù)字1 /即該位置沒有地雷,但周圍8個方向上有1顆地雷(以下同) #define NEIGHBOR_20 x02/數(shù)字2 #define NEIGHBOR_30 x03/數(shù)字3 #define NEIGHBOR_40 x04/數(shù)字4 #define NEIGHBOR_50 x05/數(shù)字5 #define NEIGHBOR_60 x06/數(shù)字6 #define NEIGHBOR_70 x07/數(shù)字7 #define NEIGHBOR_80 x08/數(shù)字8,m_map = new BYTE m_nWidth*m_nHeight ; ZeroMemory(
18、m_map, m_nWidth*m_nHeight );/系統(tǒng)函數(shù),清零內存空間,BOOL m_bWin98; CStringwinMineClassName; HWND hWinMineWnd; CRect rectWinMine; CRect rectMe; BOOL m_bStart; int m_nWidth; int m_nHeight; int m_nMineNum; int m_nMineCurNum; BYTE *m_map; BYTE m_ColorSample168,數(shù)據(jù)成員m_ColorSample數(shù)組說明: 數(shù)組大小是168,數(shù)據(jù)類型是BYTE(字節(jié)); 預存16種狀態(tài)
19、中間第8行16個像素的“顏色”。 不是真正意義上的顏色,而是將每種顏色轉換成16種自定義顏色的編號,并取編號的低4位二進制位,且將兩個顏色編號壓縮成1個字節(jié)。所以存儲16個像素的“顏色”只需8個字節(jié)即可,m_ColorSample 1 0 = 0 x78;/NEIGHBOR_1 m_ColorSample 1 1 = 0 x88; m_ColorSample 1 2 = 0 x88; m_ColorSample 1 3 = 0 x8c; m_ColorSample 1 4 = 0 xcc; m_ColorSample 1 5 = 0 x88; m_ColorSample 1 6 = 0 x88
20、; m_ColorSample 1 7 = 0 x88,自定義函數(shù):RGB顏色到16種顏色編號的轉換 BYTE CMineCrackDlg:Color256To16( COLORREF colorref ) BYTE ret; switch( colorref ) case RGB( 0, 0, 0): ret = 0 x00; break;/黑色-0 case RGB(128, 0, 0): ret = 0 x01; break;/栗色-1 case RGB( 0, 128, 0): ret = 0 x02; break;/深綠色-2 case RGB(128, 128, 0): ret =
21、 0 x03; break;/橄欖色-3 case RGB( 0, 0, 128): ret = 0 x04; break;/海軍藍色-4 case RGB(128, 0, 128): ret = 0 x05; break;/紫色-5 case RGB( 0, 128, 128): ret = 0 x06; break;/水鴨色-6 case RGB(128, 128, 128): ret = 0 x07; break;/灰色-7 case RGB(192, 192, 192): ret = 0 x08; break;/銀白色-8 case RGB(255, 0, 0): ret = 0 x0
22、9; break;/紅色-9 case RGB( 0, 255, 0): ret = 0 x0A; break;/綠色-10 case RGB(255, 255, 0): ret = 0 x0B; break;/黃色-11 case RGB( 0, 0, 255): ret = 0 x0C; break;/藍色-12 case RGB(255, 0, 255): ret = 0 x0D; break;/洋紅色-13 case RGB( 0, 255, 255): ret = 0 x0E; break;/青色-14 case RGB(255, 255, 255): ret = 0 x0F; br
23、eak;/白色-15 return ret;,顏色的壓縮(以NEIGHBOR_1這種狀態(tài)為例解釋,m_ColorSample 1 0 = 0 x78;/NEIGHBOR_1 m_ColorSample 1 1 = 0 x88; m_ColorSample 1 2 = 0 x88; m_ColorSample 1 3 = 0 x8c; m_ColorSample 1 4 = 0 xcc; m_ColorSample 1 5 = 0 x88; m_ColorSample 1 6 = 0 x88; m_ColorSample 1 7 = 0 x88,RGB( 0, 0, 0)0 RGB(128, 0
24、, 0)1 RGB( 0, 128, 0)2 RGB(128, 128, 0)3 RGB( 0, 0, 128)4 RGB(128, 0, 128)5 RGB( 0, 128, 128)6 RGB(128, 128, 128)7 RGB(192, 192, 192)8 RGB(255, 0, 0)9 RGB( 0, 255, 0)A RGB(255, 255, 0)B RGB( 0, 0, 255)C RGB(255, 0, 255)D RGB( 0, 255, 255)E RGB(255, 255, 255)F,函數(shù)成員,void StartGame( );/啟動掃雷游戲 BOOL Scan
25、TheMap( );/掃雷游戲地圖,標記每個位置的狀態(tài) BOOL ScanTheMap98( );/Win98、Win2003系統(tǒng)下掃描游戲地圖(沒有實現(xiàn)) /在m_ColorSample中查找與位置pt(開始的16個像素)顏色匹配的狀態(tài) int GetColorSample( CPoint pt ); BYTE Color256To16( COLORREF colorref );/RGB顏色到16種顏色編號的轉換 BOOL MakeDecision( BOOL *, BOOL * );/普通決策,返回:1,成功;0:繼續(xù) BOOL AdvanceDecision( BOOL *, BOOL
26、* );/高級決策 /統(tǒng)計(i,j)位置周圍8個位置上已標記為地雷的位置個數(shù) /并將8個相鄰位置中未標記為地雷的位置放入數(shù)組ptrarr中 void LookAroundDot( int, int, void *, int * ); /從位置數(shù)組ptrarr中查找位置pt,找到返回其下標,找不到則返回-1 int LookUpFromArray( const void *, CPoint,系統(tǒng)流程圖:消息和事件驅動機制,4.1 獲取并顯示操作系統(tǒng)的版本號OnInitDialog( )函數(shù),API函數(shù)GetVersion用于獲取操作系統(tǒng)的版本。 GetVersion函數(shù)的用法及例子請參考MSDN
27、。 將操作系統(tǒng)版本信息顯示在對話框的靜態(tài)文本控件中,如果想實現(xiàn)某個功能,但不知道該調用哪個API函數(shù)或MFC中的函數(shù),該怎么辦,通過google等搜索引擎查找網(wǎng)友發(fā)布的類似問題、解決方法、例子等。 關鍵字:獲取操作系統(tǒng)版本號 函數(shù)。 通過MSDN查找函數(shù)的功能及使用方法。 查閱書籍。 經(jīng)驗積累,4.2 啟動掃雷游戲StartGame( )函數(shù),通過API函數(shù)FindWindow來檢測是否存在窗口類名為“掃雷”(或“Minesweeper”)的窗口。 如果掃雷游戲未啟動,則: 獲得系統(tǒng)路徑; 獲得掃雷程序的完整路徑; 通過API函數(shù)CreateProcess來啟動掃雷游戲,程序界面采用的其他技術
28、: 判斷窗口是否是最小化狀態(tài),如果是,則正常顯示。 (如果掃雷游戲窗口被其他窗口遮住了,則)將掃雷游戲窗口調到最前面來。 激活掃雷游戲窗口,使之為當前活動窗口,4.3 并排居中顯示兩個窗口 StartGame( )函數(shù) 計算掃雷游戲地圖行數(shù)和列數(shù),效果,屏幕及程序界面尺寸參數(shù): 屏幕大小為:1280800(取決于系統(tǒng)設置)。 掃雷游戲窗口大小為:506371。 掃雷游戲邊框寬度(或高度)為:3個像素。(Win2000和WinXP系統(tǒng)) 標題欄和菜單欄高度為:48個像素。 每個方格大小為:1616像素。 掃雷游戲客戶區(qū)(去掉標題欄和菜單欄,以及邊框)大小為:500320。 客戶區(qū)中,480256
29、大小的區(qū)域用來顯示30列16行方格(高級掃雷模式);這個區(qū)域左邊有12個像素寬度的空余區(qū)域,右邊有8個像素寬度的空余區(qū)域,上面56個像素高度的區(qū)域用來顯示剩余地雷數(shù)和時間等信息,下面有8個像素高度的空余區(qū)域,窗口位置、區(qū)域大小、參數(shù)值等。 兩個坐標系,掃雷游戲地圖的行數(shù)為: m_nHeight = (客戶區(qū).bottom-客戶區(qū).top-63)/16 列數(shù)為: m_nWidth = (客戶區(qū).right-客戶區(qū).left-20)/16,4.4 開啟新局 StartGame( )函數(shù),在掃雷程序中,可以通過鼠標左鍵點擊“笑臉”按鈕、執(zhí)行“開局”菜單命令、按F2鍵3種方式來開啟新局。 本程序通過A
30、PI函數(shù)PostMessage向掃雷程序人為發(fā)送鍵盤按鍵F2的鍵盤消息,開啟新局,五、決策前的準備,準備工作:掃描游戲地圖,記錄每個方格的狀態(tài)。 在后續(xù)的決策階段需要根據(jù)這些方格的狀態(tài)信息進行普通決策和高級決策,經(jīng)過掃描后,每個方格在m_map數(shù)組中的值為以下11種情形: UNKNOW、NOMINE、ISMINE、NEIGHBOR_1、NEIGHBOR_2、NEIGHBOR_3、NEIGHBOR_4、NEIGHBOR_5、NEIGHBOR_6、NEIGHBOR_7、NEIGHBOR_8,define UNKNOW0 x00/未知 #define NOMINE0 xFF/確定沒有地雷 #defi
31、ne ISMINE0 x0F/確定為地雷 #define NEIGHBOR_10 x01/數(shù)字1 /即該位置沒有地雷,但周圍8個方向上有1顆地雷(以下同) #define NEIGHBOR_20 x02/數(shù)字2 #define NEIGHBOR_30 x03/數(shù)字3 #define NEIGHBOR_40 x04/數(shù)字4 #define NEIGHBOR_50 x05/數(shù)字5 #define NEIGHBOR_60 x06/數(shù)字6 #define NEIGHBOR_70 x07/數(shù)字7 #define NEIGHBOR_80 x08/數(shù)字8,在自動掃雷之前,將掃描結果寫入到記事本文件中: 思考
32、:怎么實現(xiàn),5.1 掃描地圖,對每行、每列上的每個方格,提取第8行16個像素的顏色,并跟預存的16種狀態(tài)的顏色進行比對,從而判定每個方格的狀態(tài)。 3個函數(shù): ScanTheMap GetColorSample Color256To16 ScanTheMap函數(shù),BOOL CMineCrackDlg:ScanTheMap( ) /掃雷游戲地圖,標記每個位置的狀態(tài) int i, j, ret; CPoint pt; BOOL finish = FALSE;/游戲是否結束(踩到了地雷)的標志 for( i=0; im_nHeight; i+ )/行 for( j=0; jm_nWidth; j+ )
33、/列,if( m_map i*m_nWidth + j != 0 ) continue; pt = CPoint( 12 + j*BMPWIDTH, 55 + i*BMPHEIGHT + 7 ); ret = GetColorSample(pt); switch( ret ) case 0:m_map i*m_nWidth + j = NOMINE; break; case 1:m_map i*m_nWidth + j = NEIGHBOR_1; break; case 2:m_map i*m_nWidth + j = NEIGHBOR_2; break; case 3:m_map i*m_n
34、Width + j = NEIGHBOR_3; break; case 4:m_map i*m_nWidth + j = NEIGHBOR_4; break; case 5:m_map i*m_nWidth + j = NEIGHBOR_5; break; case 6:m_map i*m_nWidth + j = NEIGHBOR_6; break; case 7:m_map i*m_nWidth + j = NEIGHBOR_7; break; case 8:m_map i*m_nWidth + j = NEIGHBOR_8; break; case 9:m_map i*m_nWidth
35、+ j = NOMINE; break; case 10: finish = TRUE; break;/這3種情況均表示踩到地雷 case 11: finish = TRUE; break; case 12: finish = TRUE; break; case 13: m_map i*m_nWidth + j = UNKNOW; break; case 14: m_map i*m_nWidth + j = ISMINE; break; case 15: m_map i*m_nWidth + j = UNKNOW; break; if( finish ) return FALSE; else
36、return TRUE;,在m_ColorSample中查找與位置pt(開始的16個像素)顏色匹配的狀態(tài) /通過這種方法來辨別pt位置是沒有地雷、顯示數(shù)字18等等情況,詳見位圖Sign.bmp int CMineCrackDlg:GetColorSample( CPoint pt ) BYTE ptrColor8; COLORREF colorref1, colorref2; int i; HDChDC = :GetDC( NULL ); memset(ptrColor, 0, 8); :ClientToScreen( hWinMineWnd,GetColorSample函數(shù),ptrColor
37、i = tmp14 | tmp2說明: 注意:tmp1和tmp2均為BYTE,且取值為0F,即只有低4位有數(shù)據(jù)、高4位全為0。 tmp14:把tmp1左移4位,空出的低4位補0。 | tmp2:將前面的結果“與”上tmp2,實際上是把tmp1低4位+tmp2低4位湊成1個字節(jié),ReleaseDC( NULL, hDC ); /與預存的16種狀態(tài)比對,從而判斷該位置處于什么狀態(tài) for( i=0; i16; i+ ) if( m_ColorSamplei0 = ptrColor0 /沒有匹配,為什么要將客戶區(qū)坐標轉換為屏幕坐標? 實現(xiàn)獲取掃雷游戲窗口某個像素的顏色,有兩種方法: 獲取掃雷游戲窗口
38、設備描述表的句柄hDC,然后通過hDC利用客戶區(qū)坐標獲取掃雷游戲窗口該坐標對應像素的顏色 不需要轉換坐標。 獲取整個屏幕窗口設備描述表的句柄hDC,然后通過hDC獲取屏幕上某個坐標對應像素的顏色(如果這個坐標剛好位于掃雷游戲窗口,則實際上就是獲得掃雷游戲窗口某個像素的顏色) 需要將客戶區(qū)坐標轉換成屏幕坐標,然后通過API函數(shù)GetPixel來獲取某個像素的顏色,自定義函數(shù):RGB顏色到16種顏色編號的轉換 BYTE CMineCrackDlg:Color256To16( COLORREF colorref ) BYTE ret; switch( colorref ) case RGB( 0,
39、0, 0): ret = 0 x00; break;/黑色-0 case RGB(128, 0, 0): ret = 0 x01; break;/栗色-1 case RGB( 0, 128, 0): ret = 0 x02; break;/深綠色-2 case RGB(128, 128, 0): ret = 0 x03; break;/橄欖色-3 case RGB( 0, 0, 128): ret = 0 x04; break;/海軍藍色-4 case RGB(128, 0, 128): ret = 0 x05; break;/紫色-5 case RGB( 0, 128, 128): ret
40、= 0 x06; break;/水鴨色-6 case RGB(128, 128, 128): ret = 0 x07; break;/灰色-7 case RGB(192, 192, 192): ret = 0 x08; break;/銀白色-8 case RGB(255, 0, 0): ret = 0 x09; break;/紅色-9 case RGB( 0, 255, 0): ret = 0 x0A; break;/綠色-10 case RGB(255, 255, 0): ret = 0 x0B; break;/黃色-11 case RGB( 0, 0, 255): ret = 0 x0C;
41、 break;/藍色-12 case RGB(255, 0, 255): ret = 0 x0D; break;/洋紅色-13 case RGB( 0, 255, 255): ret = 0 x0E; break;/青色-14 case RGB(255, 255, 255): ret = 0 x0F; break;/白色-15 return ret;,Color256To16函數(shù),RGB( 0, 0, 0)0 RGB(128, 0, 0)1 RGB( 0, 128, 0)2 RGB(128, 128, 0)3 RGB( 0, 0, 128)4 RGB(128, 0, 128)5 RGB( 0,
42、 128, 128)6 RGB(128, 128, 128)7 RGB(192, 192, 192)8 RGB(255, 0, 0)9 RGB( 0, 255, 0)A RGB(255, 255, 0)B RGB( 0, 0, 255)C RGB(255, 0, 255)D RGB( 0, 255, 255)E RGB(255, 255, 255)F,顏色的編號(以NEIGHBOR_1這種狀態(tài)為例解釋,m_ColorSample 1 0 = 0 x78;/NEIGHBOR_1 m_ColorSample 1 1 = 0 x88; m_ColorSample 1 2 = 0 x88; m_Col
43、orSample 1 3 = 0 x8c; m_ColorSample 1 4 = 0 xcc; m_ColorSample 1 5 = 0 x88; m_ColorSample 1 6 = 0 x88; m_ColorSample 1 7 = 0 x88,RGB( 0, 0, 0)0 RGB(128, 0, 0)1 RGB( 0, 128, 0)2 RGB(128, 128, 0)3 RGB( 0, 0, 128)4 RGB(128, 0, 128)5 RGB( 0, 128, 128)6 RGB(128, 128, 128)7 RGB(192, 192, 192)8 RGB(255, 0,
44、 0)9 RGB( 0, 255, 0)A RGB(255, 255, 0)B RGB( 0, 0, 255)C RGB(255, 0, 255)D RGB( 0, 255, 255)E RGB(255, 255, 255)F,5.2 掃雷游戲方格16種狀態(tài)的表示,狀態(tài)0:被點開了,但沒有地雷、且周圍8個位置上也沒有地雷。在map數(shù)組中存儲的值為NOMINE(0 xFF)。 狀態(tài)1:數(shù)字1,即周圍8個位置上有1顆地雷。在map數(shù)組中存儲的值為NEIGHBOR_1(0 x01)。 狀態(tài)2:數(shù)字2,即周圍8個位置上有2顆地雷。在map數(shù)組中存儲的值為NEIGHBOR_1(0 x02) 。 狀態(tài)3:
45、數(shù)字3,即周圍8個位置上有3顆地雷。在map數(shù)組中存儲的值為NEIGHBOR_1(0 x03),狀態(tài)4:數(shù)字1,即周圍8個位置上有4顆地雷。在map數(shù)組中存儲的值為NEIGHBOR_4(0 x04)。 狀態(tài)5:數(shù)字2,即周圍8個位置上有5顆地雷。在map數(shù)組中存儲的值為NEIGHBOR_5(0 x05)。 狀態(tài)6:數(shù)字3,即周圍8個位置上有6顆地雷。在map數(shù)組中存儲的值為NEIGHBOR_6(0 x06,狀態(tài)7:數(shù)字2,即周圍8個位置上有7顆地雷。在map數(shù)組中存儲的值為NEIGHBOR_7(0 x07)。 狀態(tài)8:數(shù)字3,即周圍8個位置上有8顆地雷。在map數(shù)組中存儲的值為NEIGHBOR
46、_8(0 x08)。 狀態(tài)9:做了“?”標記,但經(jīng)過決策后判定該位置上沒有地雷,所以將被點開。在自動求解過程中不會出現(xiàn)這種狀態(tài)。在map數(shù)組中存儲的值為NOMINE(0 xFF,第9種狀態(tài)說明: 如下圖所示,“?”左下角位置為(6,12)。將該位置的右邊標記為地雷,右上角標記為“?”,這時如果鼠標光標位于(6,12)位置,此時如果鼠標左右鍵同時按下(未松開),則右上角的“?”顯示為第9種狀態(tài)。如果松開鼠標左右鍵,則右上角位置將會被點開,踩到了地雷的3種狀態(tài): 狀態(tài)10:踩到地雷時所有未標記為地雷的位置都顯示出來。在map數(shù)組中不會存儲新值(其值為初始值0),但會將狀態(tài)變量finish的值設置為
47、TRUE,從而結束自動求解。 狀態(tài)11:踩到地雷時,不是地雷但被錯誤地標記為地雷的位置。其他同上。 狀態(tài)12:踩到地雷的位置。其他同上,狀態(tài)13:做了?標記。在map數(shù)組中存儲的值為UNKNOW(0 x00)。 狀態(tài)14:被標記為地雷。在map數(shù)組中存儲的值為ISMINE(0 x0F)。 狀態(tài)15:未知,即沒有做任何標記。在map數(shù)組中存儲的值為UNKNOW(0 x00),16種狀態(tài)在m_map數(shù)組中對應的值,ScanTheMap函數(shù) switch( ret ) case 0:m_map i*m_nWidth + j = NOMINE; break; case 1:m_map i*m_nWid
48、th + j = NEIGHBOR_1; break; case 2:m_map i*m_nWidth + j = NEIGHBOR_2; break; case 3:m_map i*m_nWidth + j = NEIGHBOR_3; break; case 4:m_map i*m_nWidth + j = NEIGHBOR_4; break; case 5:m_map i*m_nWidth + j = NEIGHBOR_5; break; case 6:m_map i*m_nWidth + j = NEIGHBOR_6; break; case 7:m_map i*m_nWidth + j
49、 = NEIGHBOR_7; break; case 8:m_map i*m_nWidth + j = NEIGHBOR_8; break; case 9:m_map i*m_nWidth + j = NOMINE; break; case 10: finish = TRUE; break;/這3種情況均表示踩到地雷 case 11: finish = TRUE; break; case 12: finish = TRUE; break; case 13: m_map i*m_nWidth + j = UNKNOW; break; case 14: m_map i*m_nWidth + j =
50、 ISMINE; break; case 15: m_map i*m_nWidth + j = UNKNOW; break;,define UNKNOW0 x00/未知 #define NOMINE0 xFF/確定沒有地雷 #define ISMINE0 x0F/確定為地雷 #define NEIGHBOR_10 x01/數(shù)字1 /即該位置沒有地雷,但周圍8個方向上有1顆地雷(以下同) #define NEIGHBOR_20 x02/數(shù)字2 #define NEIGHBOR_30 x03/數(shù)字3 #define NEIGHBOR_40 x04/數(shù)字4 #define NEIGHBOR_50 x
51、05/數(shù)字5 #define NEIGHBOR_60 x06/數(shù)字6 #define NEIGHBOR_70 x07/數(shù)字7 #define NEIGHBOR_80 x08/數(shù)字8,5.3 獲取每個方格第8行16個像素的顏色 并與預存的16種狀態(tài)比對,獲取每個方格(1616)的第8行16個像素的顏色,轉換成16種顏色的編號;然后壓縮成8個字節(jié)(每個位置的顏色用4位二進制表示);最后與預存的16種狀態(tài)的顏色進行比對,從而判斷每個位置處于什么狀態(tài)。 GetColorSample函數(shù)。 Color256To16函數(shù),GetColorSample函數(shù) for( i=0; i8; i+ ) colorr
52、ef1 = :GetPixel(hDC, pt.x+i*2, pt.y); colorref2 = :GetPixel(hDC, pt.x+i*2+1, pt.y); BYTE tmp1 = Color256To16(colorref1);/轉換成16色后只有低4位有效 BYTE tmp2 = Color256To16(colorref2); ptrColori = tmp14 | tmp2; /取colorref1低4位+colorref2低4位湊成1個字節(jié),例如,以下3種狀態(tài)第8行16個像素的顏色分別為: 狀態(tài)10:78、88、00、ff、00、00、08、88。 狀態(tài)11:78、88、0
53、0、99、09、90、08、88。 狀態(tài)12:79、99、00、ff、00、00、09、99,RGB( 0, 0, 0)0 RGB(128, 0, 0)1 RGB( 0, 128, 0)2 RGB(128, 128, 0)3 RGB( 0, 0, 128)4 RGB(128, 0, 128)5 RGB( 0, 128, 128)6 RGB(128, 128, 128)7 RGB(192, 192, 192)8 RGB(255, 0, 0)9 RGB( 0, 255, 0)A RGB(255, 255, 0)B RGB( 0, 0, 255)C RGB(255, 0, 255)D RGB( 0,
54、 255, 255)E RGB(255, 255, 255)F,六、決策,在獲取每個方格的狀態(tài)信息后,需要根據(jù)這些信息來做決策: 將某些位置標記為地雷或將某些位置點開。 如果掃描到某個位置為踩到地雷的狀態(tài),則提示“掃雷失敗了”。 如果判斷出所有地雷位置都正確標記了,則提示“掃雷成功”。 如果無法決策,則提示“算法不能繼續(xù)了,6.1 普通決策,策略1:如果方格(i, j)周圍8個位置中未標記方格數(shù)0,且 = 方格(i, j)本身顯示雷數(shù)值 - 周圍已標記是雷的方格數(shù),則將每個未標記位置都標記為地雷。 通過發(fā)送鼠標右鍵單擊某個位置的消息來實現(xiàn)標記該位置為地雷。 思考:根據(jù)上面的策略1,下圖哪些位置
55、可以標記為地雷,執(zhí)行策略1,需要統(tǒng)計(i, j)位置周圍8個位置上已標記為地雷的位置個數(shù),并將8個相鄰位置中未標記為地雷的位置放入數(shù)組ArrayOfCenPt中,MakeDecision函數(shù) /統(tǒng)計數(shù)字方格(i,j)周圍的8個方格中,有多少個未標記的方格 CArray ArrayOfCenPt;/存放(i,j)相鄰位置中未做標記的位置 int isMineNumOfCenPt = 0;/8個相鄰位置中,被標記為地雷的位置個數(shù) LookAroundDot( i, j,LookAroundDot函數(shù),統(tǒng)計(i,j)位置周圍8個位置上已標記為地雷的位置個數(shù) /并將8個相鄰位置中未標記為地雷的位置放入
56、數(shù)組ptrarr中 void CMineCrackDlg:LookAroundDot( int i, int j, void * ptrarr, int * isMine ) CArray * ptrArray = ( CArray * )ptrarr; int i1, j1; for( i-1=0 ? i1=i-1 : i1=i; i+1=0 ? j1=j-1 : j1=j; j+1Add(pt); else if( m_mapi1*m_nWidth + j1 = ISMINE ) (* isMine)+; /(i1,j1)位置被標記為地雷,策略1的執(zhí)行: 通過發(fā)送鼠標右鍵單擊某個位置的消息來實現(xiàn)標記該位置為地雷,MakeDecision函數(shù) /決策1:如果方格(i,j)周圍的未標記方格數(shù) = 方格(i,j)本身顯示雷數(shù)值 /周圍已標記是雷的方格數(shù) if( ArrayOfCenPt.GetSize() = m_mapi*m_nWidth + j - isMineNumOfCenPt ) for( k=0; kArrayOfCenPt.GetSize(); k+ ) /從數(shù)組中將點取出,給每個點標記“是雷”的標志,通過發(fā)送鼠標消息實現(xiàn) :PostMessage( hWinMineWnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(1
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 銷售總結課件教學課件
- 紅火蟻的預防與治療
- 教育培訓機構的年終總結
- 第二章 相互作用-三種常見力 2025年高考物理基礎專項復習
- 侵襲性肺曲霉菌病診治指南
- 氧化碳的制取的研究說課稿
- 好玩的磁鐵說課稿
- 農村水上運動中心建設合同協(xié)議書
- 污水處理廠標識系統(tǒng)招投標文件
- 投資合伙人合同協(xié)議書
- 小學主題班會 四年級英語家長會 全國通用(共15張PPT)
- 住房公積金貸款申請表
- DB32∕T 2860-2015 散裝液體化學品槽車裝卸安全作業(yè)規(guī)范
- 中端門店商務酒店運營管理HOTEL制度 亞朵人力資源部 14號 亞朵總部晉升制度-述職模板
- 呼吸衰竭課件
- 部編版五年級上冊道德與法治《期中考試試卷》(附答案解析)
- 機械加工車間低壓配電系統(tǒng)及車間變電所設計【精選文檔】
- 危重患者護理質量檢查月度分析總結
- 砌體結構承載力計算
- 醫(yī)院科室質量與安全管理記錄本精選
- 好餓的小蛇(繪本修改版)
評論
0/150
提交評論