c++開發五子棋


  本來是打算編寫這個游戲一邊寫博客的,結果太懶了,五子棋都寫好了很多天了才來寫這篇文章。那就寫一寫總結吧。

  師兄14號發了作業的題目,當時沒怎么在意,后來17號出去玩的時候才突然意識到——哦,要我寫一個五子棋,還得是人機對戰。當時就感覺要涼涼了,還有十多天,但是連c++基本的類的知識都還沒掌握。只好硬着頭皮先去看算法。算法還好,看看網上的講解和代碼,再問問師兄,大致思路差不多就理下來了。那就先來說一說算法吧:

  博弈樹 + 極大極小值搜索 + alpha-beta剪枝

  過程中看了很多的博客,這里總結一下講的較為清楚的幾篇:

       https://github.com/colingogogo/gobang_AI          這一篇的代碼比較清楚,等讀完文章慢慢搞懂算法后可以看一看這一篇的代碼

      https://blog.csdn.net/lihongxun945/article/details/50625267    //講極大極小值搜索

       https://blog.csdn.net/lihongxun945/article/details/50668253   //講alpha-beta剪枝      這兩篇講的很詳細

      https://blog.csdn.net/qq_42058018/article/details/81142881    //這一篇相對更好懂一些吧。

    說一說我的理解吧,因為發現第一次看的話確實要花一番功夫去想,那就把當時的困惑點記錄下來。

   我們人類下棋的時候怎么判斷下在哪里呢?就看看哪里對我們最有利,最有希望贏。計算機怎么看呢?就需要一個評估函數,來評估當前局勢對我的得分,得分越高就越有利。那么選出得分最高的相應位置就行啦(其實評估函數有兩種,一種是對整個棋局的評估,啟發式搜索的時候還會有一個啟發式評估函數是對某一個位置的評估。這兩個評估是不同的。

  但是呢,所謂“知己知彼,百戰不殆”。下棋如果只考慮簡單的一步棋的話,那也太吃虧了,高手都要多考慮幾步的。AI也是這樣。

下棋的時候,不是看你這一步下的有多好,而是看你能撐多久,誰撐到對方輸,誰就贏了,所謂誰笑到最后,誰笑得最好。所以,向前看步數越多的人,越能做出對未來越有利的決定,這就是博弈樹,極大極小值搜索的中心思想。

   博弈樹是用dfs來實現的,其實就是一種窮舉。先窮舉我能下的所有地方,對於我下的一個地方,窮舉對方能下的所有地方,以此類推。。。。由此生成一個博弈樹。

 

 

  實際上,對方也不傻,我們希望得分最高,對方肯定希望我們得分越低越好。所以每次輪到對方下棋,他都會選擇得分最低的地方下棋(這樣對他最有利)。可以看一看下面的博弈樹手動模擬一下,就是dfs自上而下,又自下而上的過程。(先忽略那個紅叉號,那個是剪枝用的)

 

 

  我們規定該樹的深度,假如是三,即,向前考慮三步,看我三步之后的評估函數的得分。哪種情況的得分高,就下在哪里。

  剪枝是肯定要的。因為博弈樹是成指數級上升的,不剪枝簡直就玩不下去——復雜度太高了。(更何況師兄給的棋盤是32*32的棋盤。。)

   怎么剪枝呢?簡單來說就是,如果對方發現,他下在1位置,我會得到一個分數a,但是他下在2位置,我可能會得到一個更高的分數b,那他還會再看他下在位置2我會不會得到比b更高的分數c嗎?肯定不會了,因為我至少能得到分數b,而b是比a大的,他肯定不希望我得到b而不是a,他當然希望我得分越少越好。大致思路就是這樣,具體可以看博客和代碼。

    那么我們怎么知道下一步哪些位置可以下?難道要遍歷整個棋盤嗎?那樣也太慢了吧。。我重寫了一個可遍歷的雙端隊列,每次下一個棋都把該位置周圍的位置加進去,那么哪些位置就是最有可能下棋的位置了。今天看到其實海可以再優化,啟發式搜索給節點排個序,這樣就能較早剪枝,提高效率。

  主要算法就是這么多,具體編程時還遇到了一些小問題,又添加了一些存儲的結構。這里就不詳細說了。

   當時的狀況是,算法是搞懂了,但是怎么代碼實現呢?從POP一下子轉變到OOP,對於像我這樣的菜雞真的有點難。。。於是跑去學習QT,但是QT的內容好多,那么多函數一時間也用不順手。琢磨了五六天,搞不清楚怎么寫那些類,怎么互相調用balabala。。。問來問去總算有了一點思路。

  最后一共寫了四個類,界面類,游戲類,算法類,隊列類。

  界面類完成交互和顯示;  游戲類有存儲棋盤,判斷輸贏,執行下棋等抽象操作;  算法類主要是AI的下棋算法;   隊列類重寫了隊列,實現了雙端隊列+可遍歷的特性。

  之所以沒有寫玩家類把人和AI 統一起來,是因為我的算法里這兩個的共同點比較少,所以分開寫了。

  代碼量嘛。。比較小,只有九百多行(捂臉)

  由於缺乏較大規模代碼調試的經驗(而且還是第一次寫面向對象),導致寫的過程基本沒怎么調試,寫好后就出了一堆的bug,接下來的幾天就是de呀de呀debug,本來以為要涼涼了,這下只能展示帶bug的代碼了,但是后來居然改好了,請一些朋友測試了一下,改了改參數,現在雖然不能每盤都贏,但還是有了一點水平。哈哈開心!

貼一張成果圖吧

 

 

 

 

 

PS:后來又了解了一下機器學習的內容,看了看蒙特卡洛樹搜索,發現這種五子棋算法還算是最簡單的,所以還是要繼續努力呀~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM