最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【項目實戰(zhàn)】C/C++語言帶你實現(xiàn):圍棋游戲!詳細邏輯+核心源碼

2023-02-16 17:21 作者:C語言編程__Plus  | 我要投稿

每天一個編程小項目,提升你的編程能力!


游戲介紹

下圍棋的程序,實現(xiàn)了界面切換,選擇路數(shù),和圍棋規(guī)則,也實現(xiàn)了點目功能,不過只有當所有死子都被提走才能點目,不然不準確

操作方法

鼠標操作

游戲截圖


編譯環(huán)境

VisualStudio2019,EasyX_20211109

文件描述

用廣度尋路尋找周圍所有相同棋子,直到四處碰壁了,得到包圍住自己的所有點,看看這些點是空地的數(shù)量,空地的數(shù)量就是氣的數(shù)量,氣為 0?這些子全部提掉,設為空地。每下一步棋記錄下這步棋的位置,悔棋時把這些點提掉。打劫時在存悔棋的點的地方找到劫爭的地方,只吃了一顆子并且落在劫爭的地方就不能下。

點目就是找到一塊空地,看看圍住它的是不是都是同一個顏色的子,是的話這塊空地有多大這個顏色的子的目數(shù)就加多大。

如果圍住空地的是不同顏色的子,那么這塊空地多大,這兩個子的氣就加這塊空地的目數(shù)的一半。

其他功能就是設計模式的問題了,我借鑒了 cocos2d 的設計模式,在 director 里運行整個程序,在 scene 里寫這個層運行的功能,director 的?runwithscene 寫切換場景。

詳解:

1、公共工具

MyTool

這個文件里包含了廣度尋路和圍棋地圖的類,其中圍棋地圖通過廣度尋路實現(xiàn)了吃子,提子,點目的功能。還有一些之前做七巧板的項目時保存下來的類,暫且用不到,但是也許能方便未來開發(fā),所以放到一起。

DealArray處理數(shù)組的頭文件,目前有三個函數(shù),作用分別是:將 vector 首尾顛倒、判斷一個元素是否在 vector 里面,判斷兩個 vector 是否相等(每個元素都相等就是兩個 vector 相等),函數(shù)實現(xiàn)為

MapPoint地圖點的類,由 indexX 存放列數(shù),indexY 存放行數(shù),有 PathDir 枚舉類型枚舉四個方向,能通過 MapPoint getDirPoint(PathDir turn) 這個函數(shù)獲得四個方向的點,這個函數(shù)長這樣

同時這個類也用于保存 BoundingBox 類的坐標,因為 easyx 里的每個點都是整型,所以保存的坐標也是整型。

PathNode廣度尋路的節(jié)點類,也就是樹的數(shù)據(jù)結構,一個父節(jié)點,多個子節(jié)點由

這三個數(shù)據(jù)組成,pos 是這個節(jié)點所在的位置,parent 是這個節(jié)點的父節(jié)點,child 是這個節(jié)點的子節(jié)點們

為方便清理 PathNode 節(jié)點,這個類里還提供了靜態(tài)函數(shù)

要清理掉一整個 PathNode* phead 樹只需

PathNode::clearNode(phead);

BFS廣度尋路的類,包含

四個數(shù)據(jù),用

設置地圖尺寸和判斷是否可以通行的函數(shù)指針,setMap 用法如下

初始化 AuxiliaryMap 用

清理 AuxiliaryMap 用

AuxiliaryMap(輔助地圖)的作用是每次遍歷一個廣度尋路的節(jié)點就把該節(jié)點的位置的 bool 值設為 true 表示這個點尋找過了,避免重復尋找同一個位置,尋路完就把輔助地圖清理掉。

由于不知道 ifCanThrough 是否判斷點是否在地圖內,所以要多寫一個判斷點是否在地圖內的函數(shù),避免訪問 AuxiliaryMap 時數(shù)組越界,這個函數(shù)為

現(xiàn)在輔助地圖有了,廣度尋路的節(jié)點有了,是否可以通行的判斷也有了,可以根據(jù)廣度尋路的算法用起點和終點的值找到可以通行的路徑了,尋找路徑的函數(shù)為

函數(shù)過長,就不貼出來了,廣度尋路的步驟是

1、將起點放進 PathNode* phead

2、將 phead->pos 在?AuxiliaryMap 對應的點的 bool 設為 true,即 AuxiliaryMap[phead->pos.indexY*size_Width+phead->pos.indexX]=true;

3、判斷 phead->pos 上下左右四個方向的點是否找尋過,是否可以通行,未找尋過可以通行則把這個點放入 phead 的子節(jié)點,phead->addchild(new PathNode(MapPoint(phead->pos.getDirPoint(path_up /* 或者 path_down path_left path_rght */)))); 并且放進 vector<PathNode*>child; 里

4、遍歷 child,看看有沒有點到達終點,沒有進入步驟 5,有進入步驟 8

5、令 vector<PathNode*>parent=child;child.clear(); 遍歷 parnet 里的每個 PathNode,對每個 PathNode* 單獨執(zhí)行步驟 3

6、如果 child 為空,進入步驟 7,如果 child 不為空,進入步驟 4

7、返回空的 vector<MapPoint>result;

8、把找到的 PathNode 節(jié)點保存下來,不停找 pathNode 的父節(jié)點,把每個父節(jié)點的 pos 值?push_back 進?vector<MapPoint> result; 里面返回 result.

具體函數(shù)實現(xiàn)看 BFS 里的 vector<MapPoint> getThroughPath(MapPoint?star, MapPoint?end);

實現(xiàn)這個功能其實對圍棋這個項目沒有幫助,但是都封裝出了這個類,不實現(xiàn)一下這個功能總歸有點缺憾,圍棋要判斷所有能走的點,只需要在廣度尋路的八個步驟中去掉對是否到達終點的判斷就行了,得到包圍這塊區(qū)域的點只需要在尋找所有能走的點時遇到 ifCanThrough 為?false 的點時把該點所在 AuxiliaryMap 的?bool 值設為 true 并存進 vector<MapPoint> result; 里就行,最終返回的就是遇到的所有不能走的點,在 BFS 的函數(shù)實現(xiàn)為

BFS 中還實現(xiàn)了單步尋路的功能

這個的用法是

MapNode地圖節(jié)點,我試圖用圖的數(shù)據(jù)結構來寫圍棋的地圖,這樣地圖上的每個點都是指針,加上 Map 是個單例模式,得到的每個點,點每個點的處理都會反應到真實的地圖上,不用重復傳參。

這個頭文件有 Piece 枚舉類型

表示圍棋的黑子,白子,空地三種類型

這個類有

9 個數(shù)據(jù)

要清理整個地圖調用

這個函數(shù)。這個函數(shù)不會把自己清理掉,只會把自己周圍的所有節(jié)點設為 nullptr,所以可以放心在析構函數(shù)里用它。

悔棋時把這個點設為某個棋子用

悔棋時這個點如果棋子改變次數(shù)大于 2,設為與原先相同的子時原先的子就要設為的這個子的相反面,這點有一點小邏輯在里面,當然如果改變次數(shù)為 2,要設為任何子,原來的子都會是空地。有閑心的可以自己推一下。

不悔了和落子時把這個點設為某個棋子時用

StepPoint每一步的點,用于存每一步落子的地方和每一步悔棋的地方,還有每一步劫爭的 MapNode,用于實現(xiàn)悔棋和不悔了的功能,共有

八個數(shù)據(jù),如果上邊有被吃,就把上邊的所有空地找到,設為與這一步棋子相反的棋子,下,左,右亦然,四個方向判斷完后再把這顆子提掉,這就是悔棋的邏輯,不用存下被吃掉的所有點,用四個 bool 值就省去了很多內存。


Map,地圖的所有數(shù)據(jù)及數(shù)據(jù)的處理都在 Map 這個類里。

這是個單例模式的類,單例模式就是任何人不能 new 出一個對象,只有這個類自己才能給出自己的模樣,具體寫法為

具體用法你得多多實踐才能理解透徹,例如寫一個回合制對戰(zhàn)游戲,一個英雄一個怪物,一回合輪一個人發(fā)動攻擊或者防御什么的,調整每個人的攻擊力,防御力,暴擊率,看看最后是誰贏了這個小項目,你用單例模式試著做一下差不多就能理解了。之后要說的模擬 cocos 就用到了一個單例模式,也是至關重要的單例模式。

Map 共有

這六個數(shù)據(jù),且這六個數(shù)據(jù)都是私有的

drawPiece 是個函數(shù)指針,由于地圖的不同,drawPiece 函數(shù)也會不同,所以具體情況具體賦值,這個 drawPiece 相當于一個虛函數(shù)。

為 drawPiece 賦值的接口為

Entity 是地圖數(shù)據(jù)的實體,通過不斷地訪問

這四個節(jié)點來到達地圖上的任何一個地方。具體函數(shù)為

sizeX,sizeY 是地圖尺寸,用于廣度尋路。

everyStep 儲存每一步子落在的地方,everyUndoStep 儲存每一步悔棋提掉的子所在的地方,都是 stack 結構來存的。

一開始棋盤是空的,所以通過

來初始化 Entity,sizeX,sizeY。

圍棋的流程為一個人下一顆子,判斷這顆子吃了幾顆子,把吃掉的子提掉,判斷能不能下在這里(提掉的子大于一或提掉的子為一且不在 everyStep.top().kozai 的地方,沒有提掉的子且自身的氣不為 0),能下在這里就下在這里,不能下在這里就重新下,下完輪到另一個人。吃掉子,判斷在不在劫爭的位置,判斷自身的氣是否為 0?都要判斷氣,所以首先要實現(xiàn)判斷一個區(qū)域的氣的功能。

在 Map 里判斷一個區(qū)域氣的功能我寫為兩個函數(shù)

getZoneQi 就是判斷一個區(qū)域氣的函數(shù)。

判斷一個區(qū)域的氣為 0,那就要把這塊區(qū)域設為空地,這個需要得到這塊區(qū)域所有的點,然后把這塊區(qū)域所有點設為空地,實現(xiàn)這個功能需要兩個函數(shù)

能吃子,能提子,然后才能落子,落子的功能比較復雜,函數(shù)也比較長,總的來說就是

這個函數(shù),如果這個點能落子返回 true,不能落子返回 false。具體實現(xiàn)看 gitee 上的源碼

悔棋功能寫在

不悔了的功能寫在

之所以有返回值是因為有可能沒落子就有人按悔棋,或者沒悔過棋就有人按不悔了,返回的 bool 值是悔棋和不悔了是否成功。

代碼沒什么好說的,看源碼就是了,有點長。

點目功能寫在

里,有點長,看源碼去。

至此圍棋這個游戲的邏輯已經全部實現(xiàn)了,接著就是界面的切換


2、SimulationCocos(模擬 Cocos)

模擬 Cocos 有三個模塊,Menu,Scene,Director

Menu 菜單,用于保存每個按鈕的類,每個場景里只有一個菜單,菜單里有 MenuItem (菜單項)

MenuItem菜單項,是一個雙向鏈表,每個菜單里只有一個 MenuItem 鏈表,每個 MenuItem 里包含一個 Button

Button包含三個函數(shù)指針

和一個 BoundingBox 類。

BoundingBox邊框,包含

三個數(shù)據(jù),判斷某個點是否在 BoundingBox 里面調用

當一個場景里發(fā)生了點擊反應,只需在場景的 Menu 里調用

就能判斷是否按到了某個按鈕以及得到那個按鈕的 MenuItem 值,然后調用 MenuItem 的按鈕的 ResponseFunc

當點擊反應結束時調用響應中的按鈕的 Restore 然后判斷鼠標所在的位置還在不在按鈕里面,在的話調用按鈕的 Call_Back 函數(shù),函數(shù)里面?zhèn)鞯膮⑹前粹o的邊框,用于繪制按鈕。

Scene場景,繼承自 GameNode 類,

GameNode是一個雙向鏈表,有

三個虛函數(shù),operation 是場景運行時的函數(shù),EndOperation 是令場景結束運行的函數(shù),initMySelf 是初始化場景的函數(shù)

同時還有

判斷某個場景是否和自己有血緣關系。有血緣關系返回 true,無血緣關系返回 false

在 Scene 里有

這個函數(shù)指針,也算是個虛函數(shù),交由子類實現(xiàn),子類必須實現(xiàn)這個函數(shù)指針,不然一定會報錯,所以也可以稱作不會報錯的純虛函數(shù)吧。

還有

是否退出場景的判斷

在 Scene 里實現(xiàn)了

這兩個函數(shù),operation 里面真正的精華是 Operat_Func(); 這個函數(shù),這個函數(shù)交由 Scene 的子類實現(xiàn)。Scene 的子類可以通過調用 this->EndOperation(); 這個函數(shù)退出場景。

Director,單例模式,程序運行的核心,每個 Scene 都在 Director 里運行。只有兩個數(shù)據(jù)

Director 里主要通過兩個函數(shù)來實現(xiàn) Scene 的運行和場景的切換

IsRunning 變了,temp 不變,原來的場景能運行至結束然后才跳出,釋放掉原來場景的內存接著才運行新的場景,這就是 Director 的核心邏輯,Director 需要和 Scene 互相引用,Scene 通過訪問 Director 類直接訪問當前正在運行的程序,如果 Director 不是單例模式,那么 Scene 就不能通過直接訪問類的方式訪問到當前的 Director,Director 還得傳參給 Scene,這就造成了 Scene 和?Director 互相引用,也就是未定義類型的問題。所以 Director 用單例模式會很方便。

當然,這只是我使用 Cocos2d-x 根據(jù) Cocos 的特性推測著寫的,Cocos2d-x 里有自動釋放池,寫起來估計比我這種山寨版的要好,但是我這個在 Scene 里引用了 graphics.h 頭文件,也就是可以在 Scene 里重新定義圖形界面的大小,某種意義上會比 Cocos2d 方便。

3、GameScene,LoadScene

這兩個類都繼承自 Scene,都需要實現(xiàn) initMySelf 函數(shù),不過如果要實現(xiàn)兩個場景之間的切換不能通過互相引用的方法或者分成兩個文件,一個頭文件,一個 .cpp 文件來實現(xiàn),頭一種會造成發(fā)現(xiàn)一個多次重定義的標識符,和未定義標識符的報錯,后一種會多出 140 個報錯說是什么什么字符已經定義了??傊畠蓚€文件不能互相引用,那么就是一個知道另一個,一個不知道另一個,在這種情況下要實現(xiàn)場景的切換就用到了 GameNode 的特性雙向鏈表,比如我是讓 LoadScene 文件里引用了 GameScene 的頭文件,然后在 LoadScene 的類里包含了 GameScene* scene; 在構造函數(shù)的時候

把自己設為 scene 的子節(jié)點,開始游戲時

進入 GameScene

在 GameScene 里要變回 LoadScene 只需

就行了。Director 里要是 IsRunning 和?temp 有血緣關系它是不會 delete 掉?temp 的。所以切換場景時這兩個場景都不會被清理掉。

完整的 VC 項目在 gitee 上:https://gitee.com/ProtagonistMan/weiqi

以上就是圍棋的所有邏輯了,至于代碼部分,很長,邏輯都有了就剩搬磚把大樓蓋起來,看不下去我的源碼也可以根據(jù)我的描述寫一份自己的了,我相信我描述的夠清楚了。

此外,我也給大家分享我收集的其他資源,從最零基礎開始的C語言C++教程,幫助大家在學習C語言的道路上披荊斬棘!

整理分享(多年學習的源碼、項目實戰(zhàn)視頻、項目筆記,基礎入門教程)最重要的是你可以在群里面交流提問編程問題哦!

歡迎轉行和學習編程的伙伴,利用更多的資料學習成長比自己琢磨更快哦!大家也要把握住有限的時光,抓住成長的每一次機會哦~

編程學習書籍分享:

編程學習視頻分享:


【項目實戰(zhàn)】C/C++語言帶你實現(xiàn):圍棋游戲!詳細邏輯+核心源碼的評論 (共 條)

分享到微博請遵守國家法律
商城县| 田阳县| 潜山县| 吴旗县| 上饶县| 亳州市| 西吉县| 房产| 普宁市| 大埔区| 蒙阴县| 墨玉县| 安阳县| 万州区| 小金县| 黄大仙区| 莆田市| 厦门市| 师宗县| 改则县| 霍邱县| 准格尔旗| 甘洛县| 东阳市| 美姑县| 关岭| 成武县| 永胜县| 博野县| 丹凤县| 平昌县| 都昌县| 拉萨市| 姜堰市| 牟定县| 闻喜县| 新昌县| 安乡县| 富平县| 麻江县| 寿阳县|