程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 掃雷外掛的設計與實現(二)

掃雷外掛的設計與實現(二)

編輯:Delphi

  有了前述的數據,編寫接口層似乎已經不成問題了。現在來構思一下程序運行的過程。說句實話,那種對於某種變化實時作出響應的程序,一般都用什麼方法編成,本人並不很了解,推測無非是兩種思想,一種是用一個線程不斷地對這個變化進行檢查,發現改變則動作;另一種是注冊一個類似於鉤子的東西,用回調函數來處理。無疑第二種方式要更節省系統資源,只是難在本人對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;

  =================================================================

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved