首頁 > 軟體

C語言三子棋一步步實現詳程

2022-02-11 19:07:14

遊戲思路:

1.建立初始遊戲介面選單

2.建立遊戲內容:

          初始化棋盤  列印棋盤 設定兩方棋子 

          玩家下  電腦下  判斷輸贏

程式碼行數較多,這裡我們 :

          建立 game.h 標頭檔案來宣告函數

          建立 game.c 原始檔來定義函數

          建立   test.c   原始檔來執行遊戲

一.建立選單(在test.c中)

首先我們來分析,執行程式時,我們要讓電腦顯示出 是進入遊戲還是退出遊戲,建立選單menu

要進行選擇,因此選擇 switch 語句,並且當玩家進入遊戲結束遊戲後,還要再來一把,那麼就要再一次顯示 menu,因此這裡是先進行一次的迴圈,再判斷,選擇 do...while 語句。

為了閱讀方便,我們分開寫,進行函數巢狀呼叫,如下:

void menu()
{
	printf("************************n");
	printf("******  1.play  ********n");
	printf("******  0.exit  ********n");
	printf("************************n");
}
 
 
void test()
{
	int input;
 
	do
	{
		printf("請選擇>:n");
		menu();                     //呼叫建立的選單
		scanf("%d",&input);
		switch (input)
		{
		case 1:
			printf("三子棋n");
			break;
		case 0:
			printf("退出遊戲n");
			break;
		default:
			printf("輸入錯誤,請重新輸入>:");
			break;
		}
	} while (input);
}
 
 
int main()
{
	test();
	return 0;
}

二.建立遊戲內容

1.棋盤的建立和初始化

先建立 game() 函數替代 case1 中 printf("三子棋n");

再來分析,三子棋遊戲有行列,因此我們想到二維陣列三行三列,並且都為空格,在 game 函數中建立棋盤    char board[3][3] = {0};  並且初始化棋盤,initboard(board,3,3); ,這裡的初始化棋盤函數我們直接在 game 裡呼叫,在.h裡面進行宣告,在 game.c 中進行定義:

game.h
 
void initboard(char board[3][3], int row, int col);    //初始化棋盤
game.c
 
void initboard(char board[3][3], int row, int col)     //初始化棋盤
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j=0;j<col;j++)
		{
			board[i][j] = ' ';
		}
	}
}

這裡有一點我們可以優化,若我們要建立五行五列,六行六列時,又要在三個檔案裡面都改動陣列的行列,那能不能一步到位呢?

game.h
 
//這裡我們在.h裡面用宏定義直接進行行列的表達:
 
#define ROW 3
#define COL 3
 
void initboard(char board[ROW][COL], int row, int col);    //初始化棋盤
game.c
 
void initboard(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++)
		{
			board[i][j] = ' ';
		}
	}
}
test.c
 
void game()
{
	char board[ROW][COL] = {0};
	initboard(board,ROW,COL);  //初始化棋盤
}

這樣我們只需要改變 宏定義的值,列印的棋盤行列便可以直接改變。

2.列印棋盤

在 game 函數中建立列印棋盤函數

test.c
 
void game()
{
	char board[ROW][COL] = {0};
	initboard(board,ROW,COL);  //初始化棋盤
	displayboard(board, ROW, COL);  //列印棋盤
}
game.h
 
#define ROW 3
#define COL 3
//函數宣告
void initboard(char board[ROW][COL], int row, int col);    //初始化棋盤
 
void displayboard(char board[ROW][COL], int row, int col); //列印棋盤
game.c
 
void displayboard(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++)         //三列資料
		{
			printf(" %c ",board[i][j]);
			if (j < col - 1)               //看圖可知列印2個豎分割線 因此是 col-1
				printf("|");
		}
		printf("n");                //換行列印
		//列印分割行
		if (i<row-1)                 //看圖知只列印2行分割線 因此是 row-1
		for (j = 0; j < col; j++)     //列印三列
		{
			printf("---");
			if (j < col - 1)           //看圖可知列印2個豎分割線 因此是 col-1
			printf("|");
		}
		printf("n");                  //不要忘記換行
	}
}

棋盤如下:

3.玩家下棋

在 game 函數中建立玩家下棋函數

test.c
 
void game()
{
	char board[ROW][COL] = {0};
	initboard(board,ROW,COL);  //初始化棋盤
	displayboard(board, ROW, COL);  //列印棋盤
	play_move(board, ROW, COL);   //玩家下棋
	displayboard(board, ROW, COL);  //列印棋盤       走一步列印一次
}
game.h
 
#define ROW 3
#define COL 3
//函數宣告
void initboard(char board[ROW][COL], int row, int col);    //初始化棋盤
 
void displayboard(char board[ROW][COL], int row, int col); //列印棋盤
 
void play_move(char board[ROW][COL], int row, int col);   //玩家下棋

玩家只需看棋盤輸入座標即可:

注:這裡要注意 陣列行列下標都是從0開始,因此賦子時行列必須對應的減去1

game.c
 
void play_move(char board[ROW][COL], int row, int col)   //玩家下棋
{
	int x = 0;
	int y = 0;
	printf("玩家下棋>:");
	while (1)                                          需要重複下棋,是迴圈
	{
		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] = '*';               //玩家為'*'
				break;                              //走一步後跳出,防止死迴圈
			}
			else
				printf("該座標被佔用,請重新輸入:n");
		}
 
		else
		{
			printf("座標非法,請重新輸入:n");
		}
	}
}

4.電腦下棋

在 game 函數中建立電腦下棋函數

test.c
 
void game()
{
	char board[ROW][COL] = {0};
	initboard(board,ROW,COL);  //初始化棋盤
	displayboard(board, ROW, COL);  //列印棋盤
 
	play_move(board, ROW, COL);   //玩家下棋
	displayboard(board, ROW, COL);  //列印棋盤       走一步列印一次
 
	computer_move(board, ROW, COL);  //電腦下棋
	displayboard(board, ROW, COL);   //走一步列印一次
}
 
 
void test()
{
	int input;
	srand((unsigned int)time(NULL));    //在test函數裡設定亂數,srand需在rand之前使用
	do
	{
		printf("請選擇>:n");
		menu();
		scanf("%d",&input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出遊戲n");
			break;
		default:
			printf("輸入錯誤,請重新輸入>:");
			break;
		}
	} while (input);
}
game.h
 
#include <time.h>        //設定亂數需要用到時間戳
#include <stdlib.h>      //設定亂數需要用到 srand 和rand 
 
#define ROW 3
#define COL 3
//函數宣告
void initboard(char board[ROW][COL], int row, int col);    //初始化棋盤
 
void displayboard(char board[ROW][COL], int row, int col); //列印棋盤
 
void play_move(char board[ROW][COL], int row, int col);   //玩家下棋
 
void computer_move(char board[ROW][COL], int row, int col);  //電腦下棋

用亂數設定電腦落子座標

game.c
 
void computer_move(char board[ROW][COL], int row, int col)    //電腦下棋
{
	printf("電腦下棋:n");
 
	while (1)                                 //重複下,因此是迴圈
	{
		int x = rand() % ROW;    //0~2          //電腦下棋為隨機
		int y = rand() % COL;    //0~2          //我們只需要設定亂數和亂數的範圍
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';                   //設定電腦棋子為'#'
			break;                              //走一步跳出迴圈,防止死迴圈
		}
	}
}

注意:玩家和電腦下棋均為迴圈,因此在呼叫下棋函數是都應重複呼叫,則game函數裡應為:

test.c
 
void game()
{
	char board[ROW][COL] = {0};
	initboard(board,ROW,COL);  //初始化棋盤
	displayboard(board, ROW, COL);  //列印棋盤
 
	while (1)
	{
		play_move(board, ROW, COL);   //玩家下棋
		displayboard(board, ROW, COL);
 
		computer_move(board, ROW, COL);
		displayboard(board, ROW, COL);
 
	}

5.判斷輸贏

宣告函數,並分析遊戲結果:三行相同 三列相同 對角線相同  玩家贏或電腦贏 或者是下滿棋盤平局。用不同符號表示不同結果:

game.h
 
#include <time.h>
#include <stdlib.h>
 
#define ROW 3
#define COL 3
//函數宣告
void initboard(char board[ROW][COL], int row, int col);    //初始化棋盤
 
void displayboard(char board[ROW][COL], int row, int col); //列印棋盤
 
void play_move(char board[ROW][COL], int row, int col);   //玩家下棋
 
void computer_move(char board[ROW][COL], int row, int col);  //電腦下棋
 
char is_win(char board[ROW][COL], int row, int col);  //判斷輸贏  玩家贏'*' 電腦贏'#'  平局'Q'  繼續'C'
test.c
 
void game()
{
	char board[ROW][COL] = {0};
	initboard(board,ROW,COL);  //初始化棋盤
	displayboard(board, ROW, COL);  //列印棋盤
 
	char ret = 0;                                   //建立ret方便函數返回字元
	while (1)
	{
		play_move(board, ROW, COL);   //玩家下棋
		displayboard(board, ROW, COL);
 
		ret = is_win(board, ROW, COL);              //返回字元並判斷     C為繼續
		if (ret!='C')
		{
			break;
		}
		computer_move(board, ROW, COL);
		displayboard(board, ROW, COL);
 
		ret = is_win(board, ROW, COL);               //返回字元並判斷     C為繼續
		if (ret!='C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家贏n");
	}
	else if (ret == '#')
	{
		printf("電腦贏n");
	}
	else                                    //這裡ret='Q'
	{
		printf("平局n");
	}
}

函數實現:

game.c
 
int is_full(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;                                  //沒有空的座標時返回1
}
 
 
char is_win(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][1] != ' ')
		{
			return board[i][1];
		}
	}
	//三列相同
	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 (1 == is_full(board, row, col))      //當座標沒空子時,且上述條件不成立則等於1
	{
		return 'Q';                          //返回'Q'
	}
	//繼續
	return 'C';
}

這裡平局函數is_full,在函數is_win裡呼叫,直接在game.c檔案裡面, is_win 函數外面定義就行,沒有必要放在test.c裡面單獨呼叫。

test.c和game.c都需要呼叫標頭檔案stdio.h,我們將它放入game.h裡面,並且test.c和game.c都呼叫game.h就可以了

完整程式碼

1.game.h

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
 
#define ROW 3
#define COL 3
//函數宣告
void initboard(char board[ROW][COL], int row, int col);    //初始化棋盤
 
void displayboard(char board[ROW][COL], int row, int col); //列印棋盤
 
void play_move(char board[ROW][COL], int row, int col);   //玩家下棋
 
void computer_move(char board[ROW][COL], int row, int col);  //電腦下棋
 
char is_win(char board[ROW][COL], int row, int col);  //判斷輸贏  玩家贏'*' 電腦贏'#'  平局'Q'  繼續'C'

2.game.c

#include "game.h"
//函數實現
void initboard(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++)
		{
			board[i][j] = ' ';
		}
	}
}
 
void displayboard(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++)
		{
			printf(" %c ",board[i][j]);
			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");
	}
}
 
void play_move(char board[ROW][COL], int row, int col)   //玩家下棋
{
	int x = 0;
	int y = 0;
	printf("玩家下棋>:");
	while (1)
	{
		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] = '*';
				break;
			}
			else
				printf("該座標被佔用,請重新輸入:n");
		}
 
		else
		{
			printf("座標非法,請重新輸入:n");
		}
	}
}
 
 
void computer_move(char board[ROW][COL], int row, int col)    //電腦下棋
{
	printf("電腦下棋:n");
 
	while (1)
	{
		int x = rand() % ROW;
		int y = rand() % COL;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
 
int is_full(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;
}
 
char is_win(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][1] != ' ')
		{
			return board[i][1];
		}
	}
	//三列
	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 (1 == is_full(board, row, col))
	{
		return 'Q';
	}
	//繼續
	return 'C';
}

3.test.c

#include "game.h"
 
 
 
void menu()
{
	printf("************************n");
	printf("******  1.play  ********n");
	printf("******  0.exit  ********n");
	printf("************************n");
}
 
void game()
{
	char board[ROW][COL] = {0};
	initboard(board,ROW,COL);  //初始化棋盤
	displayboard(board, ROW, COL);  //列印棋盤
 
	char ret = 0;
	while (1)
	{
		play_move(board, ROW, COL);   //玩家下棋
		displayboard(board, ROW, COL);
 
		ret = is_win(board, ROW, COL);
		if (ret!='C')
		{
			break;
		}
		computer_move(board, ROW, COL);
		displayboard(board, ROW, COL);
 
		ret = is_win(board, ROW, COL);
		if (ret!='C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家贏n");
	}
	else if (ret == '#')
	{
		printf("電腦贏n");
	}
	else
	{
		printf("平局n");
	}
}
 
 
void test()
{
	int input;
	srand((unsigned int)time(NULL));
	do
	{
		printf("請選擇>:n");
		menu();
		scanf("%d",&input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出遊戲n");
			break;
		default:
			printf("輸入錯誤,請重新輸入>:");
			break;
		}
	} while (input);
}
 
 
int main()
{
	test();
	return 0;
}

遊戲效果如下:

這樣我們簡易的三子棋就寫完啦,中間還有很多可以優化的地方,之後改進了會發布的!!!!

到此這篇關於C語言三子棋一步步實現詳程的文章就介紹到這了,更多相關C語言 三子棋內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com