• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 利用Visual C#實現Reversi游戲開發

    發表于:2007-07-14來源:作者:點擊數: 標簽:
    一、 簡介 本文將細致地介紹用C#來實現游戲Reversi的完整過程。游戲界面如下圖所示。 二、 背景 我最開始寫這個程序是為了作為學習C#和.NET編程的一個練習。Reversi-或Othello一是一個相當有趣且相當流行的游戲,它僅要求幾個基本元素和簡單的游戲規則。所以
         一、 簡介

      本文將細致地介紹用C#來實現游戲Reversi的完整過程。游戲界面如下圖所示。


      二、 背景

      我最開始寫這個程序是為了作為學習C#和.NET編程的一個練習。Reversi-或Othello一是一個相當有趣且相當流行的游戲,它僅要求幾個基本元素和簡單的游戲規則。所以,它是學習一個新的編程環境的良好選擇。

      該程序的第一個版本是一個可玩的游戲,但是缺乏一些計算機平板游戲的常規特性,例如撤消移動的能力。因此,在又學習了.NET編程的一些技巧后,我又對該游戲進行了改進。修改后的游戲在原先的圖形和人工智能方面增加了一些新特性并作了性能上的改進。

      三、 使用代碼

      你只要編譯源文件并運行結果可執行文件Reversi.exe,即可開始玩這個游戲。使用菜單或工具欄,你可以進行多方面的選擇和設置。你不妨試著在游戲中間縮放窗戶,改變顏色或交換邊界來觀察所發生的情況。

      你可能注意,在你退出該游戲時,該程序將創造一文件Reversi.xml。這個文件被使用于保存多方面設置-例如游戲選項,窗戶大小和位置以及進行玩家統計-它們在游戲重新開始時被重載。

      四、 幫助文件

      本文還提供一個Windows幫助文件,包括完整的源代碼。你可以在文檔的"help files"子目錄找到它。為了使這個幫助文件可應用于該程序,只需簡單地把文件Reversi.chm復制到可執行文件Reversi.exe所在位置即可。當然,沒有它你也可以運行此游戲,但是如果點擊"Help Topics"選項將顯示一個錯誤的話-說明該游戲主程序不能發現幫助文件。

      所有用于創建這個幫助文件的源文件包括在那個子目錄下。你可以使用微軟的HTML Help Workshop對之進行編輯并且重新編譯它。

      五、 興趣點

      相應的源文件已經被很好的注釋過了,讀者可以很容易的看懂?,F在讓我們分析一下本游戲中幾個有趣的方面。

      (一) 游戲AI

      本游戲的一個很有意思的地方是計算游戲玩家的移動,所以值得討論。本游戲使用一標準的"最小最大向前看"算法來確定玩家的最佳移動。Alpha-beta pruning被使用于改進向前搜索的效率。如果你不熟悉"最小最大向前看"算法和/或alpha-beta pruning,你可以用Google搜索來找到大量的相關信息和示例。

      當然,在游戲中可能存在的太多的移動順序將導致一個相當費時的向前搜索-要生成所有可能的移動組合需要花太長的時間。這里的例外是在游戲的結束時-此時僅剩下很少的幾個方格-大約十或二十個。此時,可以進行全部的搜索并且這時可能找到玩家的最佳移動結果。

      但是在大多數情況中,向前搜索深度必須被限定到一個數目(這基于游戲的難度設置)。因此,對于每一系列可能的行動和反向移動搜索,必須計算最后的游戲平板以決定哪個玩家最有機會贏得游戲。該計算是通過使用下列標準來計算一個等級:

      ·輸掉-讓你的對手沒有合法的移動可以迫使他輸掉這一回合,從而使你更有利于能夠在一行中再次(或多次)移動。

      ·可移動性-這是一種測算-你可以做出多少次合法的行動從而留給你的對手多少次合法的行動。類似于輸掉,其思想是,減少你的對手的選擇,從而最大化你自己的選擇。

      ·邊界-一個邊界圓盤是鄰近一個空的方格的地方。一般地,擁有大量的邊界圓盤,會給你的對手在隨后的回合中更多的可移動性。相反,擁有較少的邊界圓盤意味著你的對手將在后面有較少的可移動性。這種得分反應了你的邊界圓盤相對于你的對手的邊界圓盤數。

      ·穩定性-角圓盤是穩定的,它們永不會被翼側包圍。隨著游戲的進展,另外的圓盤也將變為穩定的。這種得分反應了你的穩定圓盤數相對于你的對手的穩定圓盤數。

      ·得分-這是在平板上你的圓盤數相對于你的對手的圓盤數之差。

      不同的權值分別被賦給這里的每一種得分(這再次依賴于游戲的當前難度設置)。通過每一種標準得分乘以它的相應權值,然后把這些值加在一起,一個平板即被賦予一個等級。一個大的負數等級代表一個平板有利于黑棋,而一個大的正數等級代表一個平板有利于白棋。因此,對于一個可能的移動集合,計算機將為當前選定顏色一方選擇最可能導致最高等級的那個移動。

      一個常數maxRank被用于一場游戲的結束。它被設置為System.Int32.MaxValue-64。這可以確保任何會導致游戲結束的移動將總是比其它移動具有更高的等級(負數或正數)。

      從系統的最大整數值減去64允許我們把最后的得分添加到等級上,這樣贏得10個圓盤將比贏得2個圓盤具有高的等級。這可以使得計算機玩家在贏了時最大化自己的得分(或在輸了時最小化對手玩家的得分)。

      當前的實現還不能匹配更好的AI玩家,但是如果它和一個小人對手(至少,這個小人對手)玩得話,已經比較難了。同樣,如果你用Google搜索一下,會找到許多描述此游戲策略和AI方法的資源。

      (二) 游戲部件

      1. 平板類

      Board類描述了一個游戲平板。它使用一個二維數組來跟蹤每個平板方格的內容,它可以是定義在類中的下列的常數值之一:

      ·Black=-1
      ·Empty=0
      ·White=1

      該類提供了兩個構造器。一個用于創建一個新的空的平板,而另一個創建一個已存在平板的拷貝。

      它提供象MakeMove()這樣的公共方法-這個方法把一個圓盤添加到平板上,并能翻動任何可翼側包圍的對手圓盤。例如,IsValidMove()可被用來確定是否一個給定的移動對于一個給定玩家是有效的。如果該給定玩家不能作任何合法的移動,HasAnyValidMove()將返回false。

      另外,它還為每一個玩家跟蹤圓盤的數目-該數目被用于機器的移動AI例程。這些數目包括圓盤總數、邊界圓盤數和每種顏色的安全圓盤(或未翻動的圓盤)數。

      2. 移動結構

      在主要的ReversiForm類中,定義了一對結構用于存儲游戲移動。這兩個結構都包含了一個行與列索引對以相應于一個特別的平板方格。
    ComputerMove結構用于計算機AI。除了移動位置之外,它還有一個等級成員。這是被用于跟蹤一次移動的好或壞-這是在向前搜索過程中決定的。

      MoveRecord結構用于存儲在游戲中每次移動的信息。為了允許移動的撤消/重做特性,建立了一個數組來跟蹤每一輪游戲中的該平板。一次移動記錄包含一個描述這次特定移動之前的游戲平板,還有用來指示哪一個玩家將做下次移動的值。針對每個玩家的每次移動建立一個相應的數組以允許游戲復位到在移動過程中的任一點的狀態。

      RestoreGameAt()方法實現把游戲復位到一個特定的移動數字。盡管它潛在地允許游戲可以恢復到當前移動歷史中的任何移動;但是,主表單程序中的菜單和工具條選項目前僅提供了一次移動的撤消/重做或所有移動的撤消/重做。一種將來的增加可能是允許用戶點擊移動列表中的項來把游戲恢復相應的移動數字。

      (三) 圖形和用戶接口

      1. 游戲平板

      平板上的方格被一個叫SquareControl的用戶控件所描述。對于每個方格都有一個這種控件顯示于游戲平板上。該控件包含信息-用于顯示方格和它的內容(空的或一個黑的或白的圓盤),包括圓盤動畫和任何高亮。

      2. 顯示圓盤

      每一個圓盤被動態繪制。其基本形狀是一個圓-具有某種高亮和一個陰影來給它一個偽裝的3D外觀。這些形狀被按比例縮放,依賴于方形控制的當前尺寸。通過以這種方式對其著色,代之使用靜態的圖像,平板可以被動態地調整大小以匹配表單窗口的大小。

      在ReversiForm內部控制的方格控件的Click事件允許用戶一次移動到一個特定的方格(假定它是一個合法的移動)。同樣,當這些選項激活時,MouseMove和MouseLeave事件被控制通過有效的移動或預覽一次移動來更新平板顯示。

      3. 移動動畫

      圓盤反轉動畫是通過使用一個定義在SquareControl類中的計數器并伴隨一個System.Windows.Forms.Timer定時器實現的?;旧?,這是一個被操作系統所控制的線程-它周期性地引發一個你的表單應用程序能夠響應的事件。

      在做一次移動后,如果移動動畫選項處于活動狀態,每個受影響的方格控制把它的計數器初始化并且激活定時器。在每次時鐘滴答響時,主表單的AnimateMove()方法被調用(見下面)。這個方法更新方格計數器并且重畫它們的顯示。該動畫基本上包含把圓盤形狀從一個圓改變成一個更扁的橢圓,然后又變回到一個完整的圓,只是以相反的顏色罷了。這個動畫的光滑度和速度依賴于初始的計數值的大小(由常數SquareControl.AnimationStart所設置)和時鐘多長時間滴答響一次(由主表單中的常數animationTimerInterval所設置)。

    利用Visual C#實現Reversi游戲開發

    (四) 玩游戲

      下列變量用于控制一次游戲過程:

    clearcase/" target="_blank" >cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    //游戲參數
    private GameState gameState;
    private int currentColor;
    private int moveNumber;


      moveNumber應該是顯然的。currentColor顯示現在輪著哪一個玩家移動(黑色或白色)。gameState被設置為下列枚舉值之一:

    //定義游戲的狀態
    private enum GameState{
     GameOver, //游戲完了(也適合于起始的狀態)
     InMoveAnimation, //產生一次移動并且該動畫是活動的
     InPlayerMove, //等待用戶移動
     InComputerMove, //等待計算機移動
     MoveCompleted //一次移動完成
     //(包括動畫,如果是活動的)
    }


      大多數游戲都是在事件驅動下玩的,因此gameState的使用允許各種事件處理器來決定要采取的適當行動。例如,當用戶點擊平板方格,SquareControl_Click()被調用。如果游戲狀態是InPlayerMove,則在那個方格上作一次移動。但是如果游戲在其它狀態,則說明還沒輪到用戶移動,所以這次點擊將被忽略。

      同樣,如果用戶點擊工具條"Undo Move"按鈕,我們想要檢查該游戲狀態來看一下是否需要做任何事情,在把游戲復位到前一次移動之前。例如,如果狀態是InMoveAnimation,那么動畫定時器需要停下來,而該方格控制需要它們的計時器并且顯示重置。如果狀態是InComputerMove,那么該程序現在在用一個獨立的線程進行一次向前搜索(見下面)-它將需要停下來。

      1. 程序流程

      下圖說明了在一個游戲過程中的通用程序流程:


      StartTurn()在每次游戲的開始當任何一個玩家做一次移動后以及無論何時執行一次撤消/重做之后被調用。它負責評估游戲狀況并且為下次移動作準備。

      它首先檢查是否當前玩家能夠作一合法的移動。如果不能,它切換到其它玩家并且檢查是否那個玩家有任何合法的移動。當兩個玩家都不能移動時,根據規則,游戲結束并且它將結束該游戲。

      否則,該函數將為當前玩家作出移動作好準備。如果當前玩家在用戶控制下,它簡單地退出。然后用戶通過在一個有效的方形上點按鼠標指針或通過輸入一個有效的列字母和行數字可以作一次移動。這將導致一次對MakePlayerMove()的調用-它完成一些清理工作,然后調用MakeMove()來實現移動。如果當前玩家在計算機控制下,它就啟動向前搜索以找到最佳移動。

      2. 使用一個工作者線程

      因為向前搜索是深度優先計算的,所以它被用一個工作者線程來專門實現;否則,主表單屏幕將被凍結并且在計算最佳移動時響應滯后。因此,StartTurn()創建一個工作者線程來執行CalculateComputerMove()方法并且啟動它。

      鎖機制被用在主游戲平板對象上以防止不滿足游戲條件。作為一個例子,MakeComputerMove()和UndoMove()方法都因游戲平板而改變。這兩個方法首先試圖把一個鎖放在它上面。因此,如果一個方法碰巧被調用,而另一個正在更新該平板時,它將被強迫等待,直到那些變化完成并且該鎖被釋放為止。

      一旦發現一個移動,CalculateComputerMove()方法完成一次回調以在主表單屏幕上運行MakeComputerMove()。這個方法鎖定平板并調用MakeMove()來實現移動。

      3. 實現移動

      MakeMove()完成實際的平板更新,把新的圓盤放置到指定的位置。它也實現一些維護如撤消/重做移動歷史和高亮搬遷任何方形等。
    然后,如果移動動畫選項置為Off狀態,它簡單地調用EndMove()-它將切換當前顏色并以一個對StartTurn()的調用啟動下一個回合。
    但是如果動畫選項置為On狀態,它將代之來初始化圓盤-使其動起來并且啟動動畫定時器。如以前所討論的,該定時器將會使AnimateMove()每幾個毫秒運行一次,更新顯示并且相應地每次減少動畫計數器。最后,該計數器將到點,而AnimateMove()將調用EndMove()來完成移動。

      (五) 未來的增強

      在玩家AI方面還有很大的改進余地。向前搜索算法可以被擴充-用打開的移動或一系列被預先定級別的角和邊模式??梢允褂眠x擇性深度,這樣查找深度可以針對對游戲有較強影響的移動(例如在角落附近)而加以擴展。另外的改進將是存儲向前搜索樹。這將使它被搜索到一個更深的層次,因為該程序不會在每次重新生成相同的移動。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>