用C語言實現五子棋遊戲
C語言寫五子棋,使用多文件形式,使用代碼看起來更好看;在這裡我實現的功能是雙人博弈,如果要實現人機對戰,那麼代碼就會很復雜;
一.main.c
在主調函數中首先要提供一個給用戶選擇的界面,在這裡我們假定選擇1為開始遊戲,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; }
函數執行開始,會在顯示框中提示用戶輸入數字,1為進入遊戲,此時會調用Game()函數;2為退出遊戲。其中while循環的作用是當用戶進入界面輸入錯誤(非0或1)或者完成一次遊戲後繼續彈出選項,隻有當輸入0才將num置為0,退出循環。
二.gobang.h
函數的頭文件,其中包含宏定義和函數的聲明,代碼如下:
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <windows.h> #define ROW 10//控制棋盤大小 #define COL 10//控制棋盤大小 #define PLAYER1 1//玩傢1的棋為 1 #define PLAYER2 2//玩傢2的棋為 2 #define NEXT 3//NEXT代表繼續 #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();//函數的聲明
三.gobang.c
五子棋的主要邏輯就是:先打印出棋盤,然後玩傢一走一步,判斷是否連成五子(若成功則跳出),在打印出走之後的棋盤,玩傢二走一步,再次判斷是否連成五子,再打印出走之後的棋盤;
所以除瞭Game()函數外還需要實現以下幾個接口:
Print()//打印棋盤 Player()//玩傢下棋 Judge//判斷是否連成五子
1.Game()
五子棋的主要代碼都會寫在這個文件裡,test.c當中必須包含頭文件test.h。Game()函數調用其他函數,實現整個下棋過程。因為兩個玩傢下棋是同樣的操作,所以調用同一個函數,隻是傳入的玩傢參數不同,定義變量who,使得每次進入while循環,who的值都會改變一次,詳細過程見如下代碼和註釋。
void Game(){ int checkerboard[ROW][COL] = { 0 };//定義一個二維數組 int result = 0;//定義變量 int who = PLAYER1;//定義變量who初始值為PLAYER1的值 while (1){//一直做循環 Print(checkerboard);//打印出初始面板 Player(checkerboard, ROW, COL, who);//玩傢開始下棋 result = Judge(checkerboard); if (result != NEXT){//判斷result的值是否等於NEXT,不等於則跳出循環 break; } who = (who == PLAYER1 ? PLAYER2 : PLAYER1);//每進入一次循環who的值都會改變一次 } 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()
打印棋盤的函數並不難實現,代碼如下:
void Print(int board[][COL]){//打印當前棋盤 //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(" . ");//打印一個點 } else{ printf(" %d ", board[i][j]);//打印出當前位置的值 } } printf("\n"); } }
3.Player()
此函數無非就是給board[x][y]按照x,y坐標賦值,賦值為PLAYER1或者PLAYER2。要註意將x,y定義為全局變量,延長其生命周期,作用是記錄每次落子位置,便於計算是否連成五子。Player()函數代碼如下:
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坐標不滿足條件則返回到while printf("Eorr\n"); continue; } if (board[x][y] == 0){//此處為初始值,可以在此處下棋 board[x][y] = c;//給board[][]賦值為PLAYER1或者PLAYER2 break;//跳出循環 } else{ printf("此處不為空,重新輸入\n:"); continue; } } }
4.Judge()
判斷是否連成五子,這是最難得一步,在這裡之前定義得八個方向就用的上瞭。連成五子無非就四種情況,橫著,豎著,斜著(兩種情況),則隻需要統計則四個方向棋子的數量。在這裡說明為什麼if()判斷中的條件是>=4。在Calculation()函數中統計某一個方向的棋子數量(那八個方向)時,當前棋子的位置已知,假如它的上方有四顆棋子,則五子已經連成,但因為計數器的初始值為0,所以此時count的值為4,函數的返回值也為4,所以在Judge()函數中,if()的條件為>=4(此時>4的情況一般不會發生)。其餘詳細代碼實現如下:
int Judge(int board[][COL]){ if (Calculation(board, U) + Calculation(board, D)>=4 || \ //統計上和下棋子數量,此時結果為豎直方向上的相同棋子數量 Calculation(board, RU) + Calculation(board, LD) >= 4 || \ //統計右上和左下棋子數量,此時結果為斜著向上的相同棋子數量 Calculation(board, R) + Calculation(board, L) >= 4 || \ //統計右和左棋子數量,此時結果為橫向上的相同棋子數量 Calculation(board, RD) + Calculation(board, LU) >= 4){ //統計右下和左上棋子數量,此時結果為斜著方向上的相同棋子數量 return board[x][y]; } for (int i = 0; i < ROW; i++){//如果還有一個坐標為初始值,遊戲繼續 for (int j = 0; j < COL; j++){ if (board[i][j] == 0){ return NEXT; } } } return DRAW;//每個坐標都不為初始值且沒人勝利,平局 } int Calculation(int board[][COL], int direction){//傳入瞭方向參數 int _x = x;//局部變量使其等於當前坐標 int _y = y;//局部變量使其等於當前坐標 int count = 0;//計數器 while (1){//一直做循環直到統計完某個方向 switch (direction){ case U://往上則y坐標不變,x坐標減一,以下情況類似 _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){//統計的某個方向已經到瞭邊界,無需統計跳出循環 break; } else{ if (board[x][y] == board[_x][_y]){//棋子和當前下的棋子相同 count++;//計數器加一 } else{ break;//棋子和當前下的棋子不同,跳出循環 } } } return count; }
我們還可以在Print()函數中加上system(“cls”),此函數為清屏操作,加上後就是在一張棋盤下棋瞭,還可以改進輸出棋子的內容,如將
這樣就可以用不同的符號代表棋子瞭,最終的運行結果如下圖:
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。