用c語言實現簡單的五子棋
這個小游戲是從零開始的實現的,框架靈感來自於小游戲《走迷宮》。
游戲代碼配置: 二維數組+簡單邏輯+getch讀取鍵盤+windows函數(刷屏,改顏色,改窗口大小)
<!--more-->
勝利畫面
娛樂畫面
整體代碼
代碼太長
移步paste
https://paste.ubuntu.com/p/PjwdHs7Vtq/
實現過程
o設計棋盤 |
o實現棋子選點下落| (主要難點)
o設定交叉下棋|
o設定勝利規則|
■設計棋盤
搭建框架
char map[1000][1000]= { "||==================================||",
"|| x ||歡樂五子棋|| o ||",
"|| ============== ||",
"[====================================]",
"[[==================================]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[ ]]",
"[[==================================]]",
"[====================================]"
本來中間想用“ + ”填充就和棋盤一樣,但太密了。就還是空格代替。
印象中五子棋棋盤應該是橫豎線交縱的,但好像僅僅以鍵盤上的字符很難實現布線。嘗試了各種符號填充(理論上'+'能實現但成像很花),jpg,最后選擇了空格,視覺效果好點**
■實現棋子選點下落(如何下棋這是個大問題)
首先要在已有棋盤框架上下棋要解決以下幾個問題
1.棋子在指定棋盤內
棋子要是下在外邊可就不好判斷了
2.棋子不可覆蓋已有棋子
還記得玩貪吃蛇刪了一些代碼,結果邊界被我給吃完了。
3.棋子能下在任何符合規定的棋盤內
因為一開始我設置棋子作為實體不可覆蓋,那假若指針被棋子圍起來了那該如何出去是個大問題。
1.一開始要構思一種控制選點下棋的思路
首先我考慮了
1.<鼠標確定下點>
這是最理想的方法,鼠標點一下,棋盤上就出現對應棋子,但問題在於就目前所學而言,鼠標來選點下棋太難實現。
於是馬上轉變另一種控制途徑
2.<鍵盤控制虛擬指針來選點>
這里我不由的想起了《啊哈c》這本書最后的游戲教學部分:走迷宮小游戲。
這個小游戲實現wasd上下左右控制小球移動,並碰到“#”可判斷不能執行移動。(簡單的if判斷該坐標是否為“#”而決定是否移動,這可以將#理解成實體了)
下面簡單說下原理,自行可以了解下小球是如何移動的,並認清問題1.2為什么存在;
ch = getch(); //獲取鍵盤命令
if ( ch == 's') //下移
{
if( map[x+1][y]!= '#')//如果不是”#“那就能移動(#變成實體)
{
map[x][y] = ' '; //原坐標還原空格
x++;
map[x][y] = 'o'; //更新下一坐標
} //看懂原理后就知道如果沒有if判斷
//小球可以隨意移動,並進過的地方都變成空格(即問題2)
}
受此啟發,假若把已有棋子和邊界都設定不可觸碰的實體,小球改成我所需要的“鼠標”,用wasd控制移動,設置鍵盤按下“L”為確認下棋,這樣問題1.2就都完美解決了。(但此時你能想到讓棋子也變成實體變成這樣會造成什么大bug嘛-后文說明)
■實現交叉下棋
很簡單的思路,如果我設定 鍵盤 “l”是下棋,那么每次按下 “l”后num++,下一步鼠標儲存的棋子就在“x”,“o”間交換。
while(num)
{
if(num % 2 != 0)
turn = 'x'; //用turn 保存狀態,並依次轉變
else
turn = 'o';
xxxxxx程序 然后 num++;
}
###
本游戲的指針可視為走迷宮的小球 “o”,按下鍵盤的“L”即會在棋盤上留下“o”的痕跡並在下一次移動時變為另一個狀態“x”即可實現交叉下棋於留下棋盤痕跡。
■設計勝利規則
走到這一步了,后面判斷勝利就不用說啦,處理水平,垂直,斜線判斷五子連珠的能力還是綽綽有余的。這里就不介紹了。
■后期找bug (這個游戲的靈魂。。)
此時看似理論已實現只需敲代碼了,結果。。。
這個局面,假設鼠標指針在小圈圈外面,,那我要下里面呢。
問題來的很突然,也很致命,我要思考如何讓鼠標移動進入實體圍成的區域內。
但恰恰是這個問題讓我想到個很巧的解決方法,
甚至實現了我預期外的效果。
解決如何思路如下
建立在上面小球移動原理上
我想到了一個用一個temp巧妙地存儲指標所在坐標之前的狀態的方法,
指標移動到一個新的坐標,先用temp儲存坐標原有狀態,再將指標存儲在坐標上打印呈現出來(作為鼠標指針顯示出來);
然后執行下一次移動時,將temp所存值還給原有坐標,新坐標重復規則。`
ch = getch();
if ( ch == 's') //下移
{ //turn是該次鼠標指針的狀態('x' or 'o');
//此時除棋盤界線 棋盤上任何坐標都是可移動的
if( map[x+1][y]!= '=' &&map[x+1][y]!= ']' &&map[x+1][y]!= '[')//防越界
{
map[x][y] = temp; //原坐標恢復原來的狀態
x++; //移動x++到新的坐標
temp = map[x][y]; //儲存新的坐標的狀態
map[x][y] = turn; //在新的坐標上打印鼠標
}
} //可以對比上面小球移動原理觀察temp的妙用
再在這個基礎上加入按下”L“才能改變狀態(下棋),這樣下來,除了棋盤邊界,每個位置都能訪問,每一個
坐標狀態都是可改動的(按下“L”更改狀態即下棋,加上判斷語句又可避免在原有基礎上下棋),所以整個棋
盤都是穩定的動態狀態。
然后猛然發現,這個temp本質不就是程序: a 與 b交換值的升級版嘛!!雖然原理簡單,但這個僅僅靠巧妙的改動,
一下子全部解決了 3 大問題,也讓我感覺打開了新世界大門。
后續
就此我的五子棋就搞完了。從有想法到做完也只用一天,想加入更多元素,但后面馬上有了個更有趣的東西“折磨”了我兩三天——搭建博客。從周二到周五三天,我忙前忙后,美化主題時在各種小問題上摔跤,三兩次把我的博客搞崩潰,最終才在今天有空在原來五子棋基礎上加入了一些細節。也寫下了這篇文章。。。
這是2019.10.18 周五的晚上
回顧起來這周收獲了很多,學了許多新東西。
做了個小游戲,在學長幫忙下用了hexo搭了一個滿意的博客,周五還初步被c語言老師教了用linux系統寫代碼,晚上又用markdown寫了一篇博客。
所以完成這篇博客這周的忙碌也告一階段了。
希望下周也能很充實
希望后續能記錄更多有趣的東西~