用C語(yǔ)言實(shí)現(xiàn)五子棋游戲
C語(yǔ)言寫(xiě)五子棋,使用多文件形式,使用代碼看起來(lái)更好看;在這里我實(shí)現(xiàn)的功能是雙人博弈,如果要實(shí)現(xiàn)人機(jī)對(duì)戰(zhàn),那么代碼就會(huì)很復(fù)雜;
一.main.c
在主調(diào)函數(shù)中首先要提供一個(gè)給用戶(hù)選擇的界面,在這里我們假定選擇1為開(kāi)始游戲,2為退出游戲,代碼如下:
#include "gobang.h" void Mean(){ printf("-----------------------\n"); printf(" 1.play 2.drop up\n"); printf("-----------------------\n"); } int main(){ int seclet = 0; int c = 0; while (!c){ Mean(); printf("Please choose number:\n"); scanf("%d", &seclet); switch (seclet){ case 1: Game(); break; case 2: c = 1; break; default: printf("Please Enter Once:\n"); break; } } printf("Byebye~\n"); system("pause"); return 0; }
函數(shù)執(zhí)行開(kāi)始,會(huì)在顯示框中提示用戶(hù)輸入數(shù)字,1為進(jìn)入游戲,此時(shí)會(huì)調(diào)用Game()函數(shù);2為退出游戲。其中while循環(huán)的作用是當(dāng)用戶(hù)進(jìn)入界面輸入錯(cuò)誤(非0或1)或者完成一次游戲后繼續(xù)彈出選項(xiàng),只有當(dāng)輸入0才將num置為0,退出循環(huán)。
二.gobang.h
函數(shù)的頭文件,其中包含宏定義和函數(shù)的聲明,代碼如下:
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <windows.h> #define ROW 10//控制棋盤(pán)大小 #define COL 10//控制棋盤(pán)大小 #define PLAYER1 1//玩家1的棋為 1 #define PLAYER2 2//玩家2的棋為 2 #define NEXT 3//NEXT代表繼續(xù) #define DRAW 4//DRAW代表平局 #define U 10//上 #define RU 11//右上 #define R 12//右 #define RD 13//右下 #define D 14//下 #define LD 15//左下 #define L 16//左 #define LU 17//左上 extern void Game();//函數(shù)的聲明
三.gobang.c
五子棋的主要邏輯就是:先打印出棋盤(pán),然后玩家一走一步,判斷是否連成五子(若成功則跳出),在打印出走之后的棋盤(pán),玩家二走一步,再次判斷是否連成五子,再打印出走之后的棋盤(pán);
所以除了Game()函數(shù)外還需要實(shí)現(xiàn)以下幾個(gè)接口:
Print()//打印棋盤(pán) Player()//玩家下棋 Judge//判斷是否連成五子
1.Game()
五子棋的主要代碼都會(huì)寫(xiě)在這個(gè)文件里,test.c當(dāng)中必須包含頭文件test.h。Game()函數(shù)調(diào)用其他函數(shù),實(shí)現(xiàn)整個(gè)下棋過(guò)程。因?yàn)閮蓚€(gè)玩家下棋是同樣的操作,所以調(diào)用同一個(gè)函數(shù),只是傳入的玩家參數(shù)不同,定義變量who,使得每次進(jìn)入while循環(huán),who的值都會(huì)改變一次,詳細(xì)過(guò)程見(jiàn)如下代碼和注釋。
void Game(){ int checkerboard[ROW][COL] = { 0 };//定義一個(gè)二維數(shù)組 int result = 0;//定義變量 int who = PLAYER1;//定義變量who初始值為PLAYER1的值 while (1){//一直做循環(huán) Print(checkerboard);//打印出初始面板 Player(checkerboard, ROW, COL, who);//玩家開(kāi)始下棋 result = Judge(checkerboard); if (result != NEXT){//判斷result的值是否等于NEXT,不等于則跳出循環(huán) break; } who = (who == PLAYER1 ? PLAYER2 : PLAYER1);//每進(jìn)入一次循環(huán)who的值都會(huì)改變一次 } Print(checkerboard);//打印出最終的面板 switch (result){ case PLAYER1://返回值為PLAYLER1,玩家一勝利 printf("PLALYER1 win\n"); break; case PLAYER2://返回值為PLAYER2,玩家二勝利 printf("PLAYER2 win\n"); break; case DRAW://返回值為DRAW,平局 printf("IS DRAW"); break; } }
2.Print()
打印棋盤(pán)的函數(shù)并不難實(shí)現(xiàn),代碼如下:
void Print(int board[][COL]){//打印當(dāng)前棋盤(pán) //system("cls"); printf(" "); for (int i = 0; i < ROW; i++){//打印出橫著1到10 printf(" %d ", i); } printf("\n"); for (int i = 0; i < ROW; i++){ printf("%d", i); for (int j = 0; j < COL; j++){ if (board[i][j] == 0){ printf(" . ");//打印一個(gè)點(diǎn) } else{ printf(" %d ", board[i][j]);//打印出當(dāng)前位置的值 } } printf("\n"); } }
3.Player()
此函數(shù)無(wú)非就是給board[x][y]按照x,y坐標(biāo)賦值,賦值為PLAYER1或者PLAYER2。要注意將x,y定義為全局變量,延長(zhǎng)其生命周期,作用是記錄每次落子位置,便于計(jì)算是否連成五子。Player()函數(shù)代碼如下:
int x = 0;//全局變量x int y = 0;//全局變量y
void Player(int board[][COL],int row,int col,int c){ while (1){ printf("Please Enter x y:\n"); scanf("%d%d",&x,&y); if (x<0 || x>row - 1 || y<0 || y>col - 1){//x,y坐標(biāo)不滿(mǎn)足條件則返回到while printf("Eorr\n"); continue; } if (board[x][y] == 0){//此處為初始值,可以在此處下棋 board[x][y] = c;//給board[][]賦值為PLAYER1或者PLAYER2 break;//跳出循環(huán) } else{ printf("此處不為空,重新輸入\n:"); continue; } } }
4.Judge()
判斷是否連成五子,這是最難得一步,在這里之前定義得八個(gè)方向就用的上了。連成五子無(wú)非就四種情況,橫著,豎著,斜著(兩種情況),則只需要統(tǒng)計(jì)則四個(gè)方向棋子的數(shù)量。在這里說(shuō)明為什么if()判斷中的條件是>=4。在Calculation()函數(shù)中統(tǒng)計(jì)某一個(gè)方向的棋子數(shù)量(那八個(gè)方向)時(shí),當(dāng)前棋子的位置已知,假如它的上方有四顆棋子,則五子已經(jīng)連成,但因?yàn)橛?jì)數(shù)器的初始值為0,所以此時(shí)count的值為4,函數(shù)的返回值也為4,所以在Judge()函數(shù)中,if()的條件為>=4(此時(shí)>4的情況一般不會(huì)發(fā)生)。其余詳細(xì)代碼實(shí)現(xiàn)如下:
int Judge(int board[][COL]){ if (Calculation(board, U) + Calculation(board, D)>=4 || \ //統(tǒng)計(jì)上和下棋子數(shù)量,此時(shí)結(jié)果為豎直方向上的相同棋子數(shù)量 Calculation(board, RU) + Calculation(board, LD) >= 4 || \ //統(tǒng)計(jì)右上和左下棋子數(shù)量,此時(shí)結(jié)果為斜著向上的相同棋子數(shù)量 Calculation(board, R) + Calculation(board, L) >= 4 || \ //統(tǒng)計(jì)右和左棋子數(shù)量,此時(shí)結(jié)果為橫向上的相同棋子數(shù)量 Calculation(board, RD) + Calculation(board, LU) >= 4){ //統(tǒng)計(jì)右下和左上棋子數(shù)量,此時(shí)結(jié)果為斜著方向上的相同棋子數(shù)量 return board[x][y]; } for (int i = 0; i < ROW; i++){//如果還有一個(gè)坐標(biāo)為初始值,游戲繼續(xù) for (int j = 0; j < COL; j++){ if (board[i][j] == 0){ return NEXT; } } } return DRAW;//每個(gè)坐標(biāo)都不為初始值且沒(méi)人勝利,平局 } int Calculation(int board[][COL], int direction){//傳入了方向參數(shù) int _x = x;//局部變量使其等于當(dāng)前坐標(biāo) int _y = y;//局部變量使其等于當(dāng)前坐標(biāo) int count = 0;//計(jì)數(shù)器 while (1){//一直做循環(huán)直到統(tǒng)計(jì)完某個(gè)方向 switch (direction){ case U://往上則y坐標(biāo)不變,x坐標(biāo)減一,以下情況類(lèi)似 _x--; break; case D: _x++; break; case L: _y--; break; case R: _y++; break; case RU: _x--; _y++; break; case RD: _x++; _y++; break; case LD: _x++; _y--; break; case LU: _x--; _y--; break; default: break; } if (_x<0 || _x>ROW - 1 || _y<0 || _y>COL - 1){//統(tǒng)計(jì)的某個(gè)方向已經(jīng)到了邊界,無(wú)需統(tǒng)計(jì)跳出循環(huán) break; } else{ if (board[x][y] == board[_x][_y]){//棋子和當(dāng)前下的棋子相同 count++;//計(jì)數(shù)器加一 } else{ break;//棋子和當(dāng)前下的棋子不同,跳出循環(huán) } } } return count; }
我們還可以在Print()函數(shù)中加上system("cls"),此函數(shù)為清屏操作,加上后就是在一張棋盤(pán)下棋了,還可以改進(jìn)輸出棋子的內(nèi)容,如將
這樣就可以用不同的符號(hào)代表棋子了,最終的運(yùn)行結(jié)果如下圖:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 基于C語(yǔ)言實(shí)現(xiàn)五子棋游戲完整實(shí)例代碼
- C語(yǔ)言實(shí)現(xiàn)五子棋小游戲
- C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易五子棋
- C語(yǔ)言實(shí)現(xiàn)五子棋游戲
- C語(yǔ)言編寫(xiě)五子棋游戲
- C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋小游戲
- 基于C語(yǔ)言實(shí)現(xiàn)五子棋游戲
- C語(yǔ)言實(shí)現(xiàn)五子棋人人對(duì)戰(zhàn)
- C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易五子棋小游戲
- 用C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋小游戲
相關(guān)文章
c語(yǔ)言:基于函數(shù)指針的兩個(gè)示例分析
本篇文章是對(duì)c語(yǔ)言中函數(shù)指針的兩個(gè)示例做了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05基于C++編寫(xiě)一個(gè)簡(jiǎn)單的服務(wù)器
這篇文章主要為大家詳細(xì)介紹了如何基于C++編寫(xiě)一個(gè)簡(jiǎn)單的服務(wù)器,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴可以了解一下2023-03-03C語(yǔ)言實(shí)現(xiàn)時(shí)區(qū)轉(zhuǎn)換函數(shù)的實(shí)例
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)時(shí)區(qū)轉(zhuǎn)換函數(shù)的實(shí)例的相關(guān)資料,這里分析需求并提供實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-08-08C++基礎(chǔ)入門(mén)教程(五):new和delete
這篇文章主要介紹了C++基礎(chǔ)入門(mén)教程(五):new和delete,本文講解了動(dòng)態(tài)分配內(nèi)存、new和delete的配對(duì)、new、delete與reatin、release的關(guān)系、動(dòng)態(tài)數(shù)組等內(nèi)容,需要的朋友可以參考下2014-11-11C++中類(lèi)的構(gòu)造函數(shù)初始值列表解讀
這篇文章主要介紹了C++中類(lèi)的構(gòu)造函數(shù)初始值列表,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)系列之樹(shù)的概念結(jié)構(gòu)和常見(jiàn)表示方法
本章將正式開(kāi)啟數(shù)據(jù)結(jié)構(gòu)中?“樹(shù)”?部分的講解,本章將介紹樹(shù)的概念和結(jié)構(gòu),以及樹(shù)的表示方法,感興趣的朋友進(jìn)來(lái)看看吧2022-02-02