有了前述的數據,編寫接口層似乎已經不成問題了。現在來構思一下程序運行的過程。說句實話,那種對於某種變化實時作出響應的程序,一般都用什麼方法編成,本人並不很了解,推測無非是兩種思想,一種是用一個線程不斷地對這個變化進行檢查,發現改變則動作;另一種是注冊一個類似於鉤子的東西,用回調函數來處理。無疑第二種方式要更節省系統資源,只是難在本人對Windows的鉤子掌握的還一塌糊塗。若換了個高手,無疑應該用這種方式,而我卻只有望著Spy++中迅速滾動的消息發呆的份。也許等我學好了鉤子之後,會寫個0.2版,而在0.1版中我已經決定了使用丑陋的反復檢查的方式。於是,用了一個TTimer控件,定時間隔設在了30左右,用它的OnTimer事件來進行一次檢查和反饋操作。時間間隔是反復試驗確定的,太小,會很占CPU,太大則反應會變慢。
這樣,運行過程已經確定下來:
OnTimer事件->判斷當前可否進行操作->取得整個雷區當前狀況->用算法進行分析->反饋操作
所謂不可進行操作的時候,無非是指:根本沒有掃雷窗口,或者窗口部分被遮擋(此時無法取得正確的像素值),或者掃雷游戲沒有開始。
在我的代碼中,OnTimer事件處理過程的核心就是如下簡單的幾句:
=================================================================
if GetMineWindow then
begin
FetchCells;
AnalyzeCells;
OperateCells;
end;
=================================================================
其中:
GetMineWindow函數返回一個Boolean值,表示可否進行操作。如果可以,同時將關於掃雷窗口的一些參數存放進全局變量中。
FetchCells過程取得整個雷區所有方塊的信息,填入輸入緩沖區。
AnalyzeCells過程對輸入緩沖區中的數據進行分析,將反饋操作填入輸出緩沖區。
OperateCells過程根據輸出緩沖區中的數據對掃雷窗口進行反饋操作。
上述輸入緩沖區和輸出緩沖區,各是一個二維數組,直觀地對應了掃雷窗口上的每一個方塊。前者保存每個方塊的當前狀態供分析,後者保存分析完畢後,將要實施到每一個方塊的操作。雷區的寬和高都不是固定的,而這兩個二維數組,則無論何時都要能夠保存所有方塊的信息。這時有兩個選擇,一是定義足以容下最大情況的靜態數組,二是使用動態數組。為了簡單,我采用了前者,畢竟最大情況也不是大得難以忍受。這樣,還需要一對整型變量保存實際雷區的寬和高。
現在可以來看一下全部需要的全局常量,變量和類型:
=================================================================
const
MINE_WINDOW_TITLE = '掃雷'; //窗口標題,供尋找掃雷窗口用
//以下四個,為雷區四邊到窗口客戶區四邊的距離
TOP_MARGIN = 55; //上邊距
BOTTOM_MARGIN = 8; //下邊距
LEFT_MARGIN = 12; //左邊距
RIGHT_MARGIN = 8; //右邊距
CELL_WIDTH = 16; //每個方塊寬度
CELL_HEIGHT = 16; //每個方塊高度
MAX_COLUMN_COUNT = 30; //雷區最大可能的列數
MAX_ROW_COUNT = 24; //雷區最大可能的行數
type
//每個方塊的可能狀態,包括0~8的數字(0不顯示),未知的,已插旗標記為雷的,和標記問號的
TCellState = (cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, cs8, csUnknown, csMarked, csPossible);
//TCellState的集合類型,供分析算法使用
TCellStates = set of TCellState;
//對每個方塊的操作種類,包括無操作,左鍵單擊,右鍵單擊,左右鍵同時單擊,和右鍵雙擊(用於將問號標記成旗)
TOperation = (opNone, opLeftClick, opRightClick, opBothClick, opRightDoubleClick);
var
MineWnd: HWND; //保存掃雷窗口的句柄
MineDC: HDC; //保存掃雷窗口的設備上下文
//雷區的實際寬度和高度(方塊數)
AreaWidth: Integer
AreaHeight: Integer;
//輸入緩沖區
Cells: array[0..MAX_COLUMN_COUNT-1, 0..MAX_ROW_COUNT-1] of TCellState;
//輸出緩沖區
Operations: array[0..MAX_COLUMN_COUNT-1, 0..MAX_ROW_COUNT-1] of TOperation;
=================================================================