詳解!C語言程式設計實現小遊戲“三子棋”
今天我們來程式設計實現一個充滿童趣的小遊戲“三子棋”
先來說一下三子棋的規則:
三子棋又叫九宮棋、圈圈叉叉、一條龍等。
將正方形對角線連起來,或相對兩邊依次擺上三個雙方棋子,
總之只要將自己的三個棋子走成一條線,
對方就算輸了。
不用再過多解釋了,相信大家一定都玩過!
那麼,該如何用程式設計的方式實現它呢?
首先,我們建立專案後,要建立三個檔案
分別是標頭檔案game.h,用來宣告庫函式,儲存我們在程式設計中所自定義函式的函式名,以及巨集定義棋盤的寬高。
原始檔game.c檔案用於儲存我們所編寫的遊戲中所要用到的自定義的函式體。
而test.c中包含的是整個遊戲程式的大框架和遊戲選單程式。
我們先在test.c檔案中定義選單函式,並在主函式中呼叫
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> void menu() { printf("***********************************\n"); printf("************ 1.play ************\n"); printf("************ 0.exit ************\n"); printf("***********************************\n"); } int main() { int input = 0; printf("歡迎啟動三子棋!\n"); do { menu(); printf("請選擇:"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出遊戲\n"); break; default: printf("輸入錯誤,請重新輸入!\n"); break; } } while (input); return 0; }
除錯成功後是這樣子的:
接下來就是最重要的game()程式體了
首先要展出棋盤,
我們知道三子棋的棋盤是一個3x3的正方形格子,即九宮格。
在程式執行後可以是這樣子
我們在game.h檔案中定義寬高
#define ROW 3
#define COL 3
接下來再game.c中寫出初始化陣列的程式,在遊戲一開始時將陣列中的所有元素初始為“ ”(空格)
void InitBoard(char board[ROW][COL], int row, int col) { memset(&board[0][0], ' ', row*col*sizeof(board[0][0])); }
這裡我們使用memset函式,記得加上宣告
#include <string.h>
接著寫出展出棋盤的函式
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i<row; i++)
{
int j = 0;
for (j = 0; j<col; j++)
{
printf(" %c ", board[i][j]);//這裡是 空格+%c+空格 //
if (j<col - 1)
printf("|");
}
printf("\n");
if (i<row - 1)
{
for (j = 0; j<col; j++)
{
printf("---");
if (j<col - 1)
printf("|");
}
printf("\n");
}
}
}
這樣就可以實現上圖的效果,
棋盤的展出與初始化完成
接下來我們定義讓玩家先走,於是寫出玩家走棋的函式
玩家走的棋用’X’來表示
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:\n");
while (1)
{
printf("請輸入走的座標:");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷玩家所輸入的座標是否在棋盤內//
{
if (board[x - 1][y - 1] == ' ')//判斷所輸入的座標是否已被佔用//
{
board[x - 1][y - 1] = 'X';
break;
}
else
{
printf("抱歉,座標已經被佔用,請重新輸入!\n");
}
}
else
{
printf("輸入的座標有誤,請重新輸入!\n");
}
}
}
接著寫出電腦走棋的函式
電腦走的棋用’O’來表示
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦走:\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = 'O';
break;
}
}
}
這裡我們用到了rand函式,令電腦在沒佔用的位置隨機走一步棋
需要進行宣告
#include <stdlib.h>
並且需要在主函式下呼叫srand函式
同時宣告
#include <time.h>
最後,需要定義一個函式來判斷輸贏或平局
我們在構成獲勝條件時讓函式的返回值為棋子所用的字元
在函式的末尾我們還需要一個用於判斷棋盤是否被佔滿的函式IsFull(在下方說明),
佔滿時返回’Q’否則返回‘ ’
當返回值為‘ ’時未出現獲勝方,則應繼續遊戲
當返回‘Q’時意味著沒有一方獲勝,而棋盤已被佔滿,即為平局
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i<row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
for (i = 0; i<col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
return board[1][1];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
return board[1][1];
if (IsFull(board, row, col) == 1)
{
return 'Q';
}
return ' ';
}
IsFull函式用於判斷棋盤是否被佔滿,未被佔滿返回值為0,佔滿時返回1
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i<row; i++)
{
for (j = 0; j<col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
(以上函式均寫在檔案game.c中)
這時我們就可以寫出game函數了
每當完成一步棋後都需要呼叫IsWin函式來進行一次判斷
void game()
{
char board[ROW][COL] = { 0 };
char ret = 0;
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
while (1)
{
PlayerMove(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != ' ')
break;
DisplayBoard(board, ROW, COL);
ComputerMove(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != ' ')
break;
DisplayBoard(board, ROW, COL);
}
if (ret == 'X')
printf("玩家贏!\n");
else if (ret == 'O')
printf("電腦贏!\n");
else if (ret == 'Q')
printf("平局\n");
DisplayBoard(board, ROW, COL);
}
三子棋函式完成!
你是否找回了童趣呢?
完整程式碼:https://github.com/Yubao-wss/Game/tree/master/Sanzi Chess/Sanzi Chess