1. 程式人生 > >[日常練習] 3. 基於井字棋遊戲的C語言實現!

[日常練習] 3. 基於井字棋遊戲的C語言實現!


井字棋算是童年課堂上的與同桌默契配合的一大樂趣...躲避著老師“關切”的目光,在眼皮底下“頂風作案”,將“燈下黑”體現的淋漓盡致!在C語言中,也算是一個小的專案,今天,我們就用C語言來實現它!!!追逐童年的一份小樂趣!


遊戲介紹:

“井字棋”也稱“三子棋”,需要一個3*3的棋盤。假設分為黑、白方,各執黑棋、白棋,雙方各下一次,下棋位置必須在棋盤內並且不能佔著已有棋子,若能將橫3、豎3、斜3任意一種情況都是黑棋/白棋,那麼則黑方/白方勝利。要是當棋盤下滿還不能分出勝負,那麼就是平局。

C語言實現邏輯:

1. 首先,需要一個3*3的棋盤,棋盤使用二維陣列配合字元進行列印即可,採用迴圈結構可以方便我們的操作。

2. 遊戲簡答可分成:玩家、電腦雙方,那麼電腦下棋子與玩家下棋子的棋盤都需要進行列印。這是兩種不同的重複操作,但大致功能相同,那麼可以根據其功能寫出兩種列印函式。

3. 雙方落子是依據在二維陣列之內的,給兩者不同的字元標識即可進行區分。但是落子規則需要進一步討論,玩家所輸入座標必須在滿足二維陣列的要求,不能是負數、不能越界,否則應該重新進行座標輸入。還有一種情況就是,所輸入座標已經有棋子了,這時應該提示玩家重新進行輸入,並且電腦應該直接避免這個情況。

4. 判斷勝負是遊戲很重要的一部分。這一部分也是依據在二維陣列的基礎上的,可以遍歷二維陣列的元素,要是橫、豎、斜之一存在相同的棋子,那麼執該棋子方取得勝利。否則當棋盤填充滿的情況下,仍無勝利方,那麼就是平局了。


經過上面簡單的邏輯分析,為了驗證我們邏輯的正確性,現在給出我們的C語言實現的原始碼及結果!

測試原始碼:

#include <stdio.h>
#include "game.h"
#include <time.h>
#include <stdlib.h>

void menu()        //列印遊戲選單
{
	printf("************************************\n");
	printf("********《《    1. play    》》*********\n");
	printf("********《《    0. exit    》》*********\n");
	printf("************************************\n");
}

void game()
{
	char board[ROW][COL] = {0};       //以行列作為二維陣列的引數值
	char ret = 0;                     //字元型別ret作為載體,便於二維陣列中所傳字元進行比對
	InitBoard(board, ROW, COL);       //定義一個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);//電腦走(一定是空白可賦值,見25--28行)
		ret = IsWin(board, ROW, COL); //判定勝負
		if(ret != ' ')                
		{
			break;
		}
		DisplayBoard(board, ROW, COL);//電腦走後,列印棋盤
	}
	if(ret == '0')                    //
	{
		printf("電腦贏!\n");
	}
	else if(ret == 'X')
	{
		printf("玩家贏!\n");
	}
	else if(ret == 'Q')
	{
		printf("平局!\n");
	}
}


void test()
{
	int input = 0;                        
	srand((unsigned int)time (NULL));       
	do
	{
		menu();
		printf("請選擇:>");            //選擇開始遊戲
		scanf("%d", &input);            //輸入選項
		switch(input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出遊戲\n");
			break;
		default:
			printf("選擇錯誤,請重新選擇!\n");
		}
	}while(input);                    //迴圈結構,輸錯後繼續,不準停!
}

int main()
{
	test();
	return 0;
}

遊戲實現原始碼:

#include "game.h"

void InitBoard(char arr[ROW][COL], int row, int col)   //函式不需返回值,需要二維陣列、行數、列數作為函式引數
{
	int i = 0;                          //注:在從game.h拷貝函式名的時候需要去除 ";" 否則會提示錯誤:在檔案範圍內找到“{”(是否缺少函式頭?)
	int j = 0;

	for(i=0; i<row; i++)
	{
		for(j=0; j<col; j++)        //遍歷二維陣列
		{
			arr[i][j] = ' ';        //初始化二維陣列
		}
	}
}

void DisplayBoard(char arr[ROW][COL],int row, int col)   //函式引數與InitBoard相同,功能為列印有邊界的棋盤,即給二維陣列賦值
{
	int i = 0;
	int j = 0;

	for(i=0; i<row; i++)                                //遍歷二維陣列
	{
		for(j=0; j<col; j++)
		{
			printf(" %c ", arr[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 PlayerMove(char arr[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<=3)&&((y>=1 && x<=3)))                     //保證玩家輸入座標正確性
		{
			if(arr[x-1][y-1] == ' ')                             //玩家輸入座標與二維陣列下標之間相差1
		{
			arr[x-1][y-1] = '*';                                 //如果為空,即未被佔用,則賦值為字元X
			break;
		}
			else
		{
			printf("座標已被佔用\n");                            //被佔用提示
		}
	}
		else                                                     //不在if語句限值之內即非法
		{
			printf("座標非法\n"); 
		}                         
	}
}

void ComputerMove(char arr[ROW][COL],int row, int col)           //電腦落子
{
	int x = 0;
	int y = 0;
	printf("電腦走:>\n");
	while(1)
	{
		x=rand() % 3;                                              //得二維陣列下標0  1  2,對3取模即可
     	y=rand() % 3;
		if(arr[x][y] == ' ')                                
		{
			arr[x][y] = 'o';                                     //若為空,對其賦值
			break;
		}
	}
	printf("電腦座標:%d %d\n", x+1, y+1);
}    

//當程序沒有退出時 會產生錯誤  1>LINK : fatal error LNK1104: 無法開啟檔案“E:\A-bite\A\game\Debug\game.exe”

static int IsFull(char arr[ROW][COL],int row, int col)  //不為介面函式,不需要放入game.h,僅在此使用,無法進行test.c中呼叫
{
	int i = 0;
	int j = 0;

	for(i=0; i<row; i++)                                //遍歷二維陣列
	{
		for(j=0; j<col; j++)
		{
			if(arr[i][j] == ' ')                        //判斷是否仍有空值
				return 0;                               //有空值返回0
		}
	}
	return 1;                                           //無空值返回1
}

char IsWin(char arr[ROW][COL],int row, int col)         //判斷勝負
{
	int i = 0;
	for(i=0; i<row; i++)                                //判斷行  是否能勝利
	{
		if(arr[i][0]==arr[i][1] && arr[i][1]==arr[i][2] && arr[i][0]!=' ')
		{
			return arr[i][0];                           //若三子相同,且不能為空,返回元素內值
		}
	} 

	for(i=0; i<col; i++)                                //判斷列  是否能勝利
	{
		if(arr[0][i]==arr[1][i] && arr[1][i]==arr[2][i] && arr[1][i]!=' ')
		{
			return arr[1][i];
		}
	}

	if(arr[0][0]==arr[1][1] && arr[1][1]==arr[2][2] && arr[1][1] != ' ')   //判斷正對角線能否勝利
	{
		return arr[1][1];
	}

	if(arr[0][2]==arr[1][1] && arr[1][1]==arr[2][0] && arr[1][1] != ' ')   //判斷反對角線能否勝利
	{
		return arr[1][1];
	}

	if(IsFull(arr, row, col))                                              //判定平局
	{
		return 'Q';
	}
	return  ' ';                                     //繼續
}

標頭檔案及函式宣告:

#ifndef __GAME_H__
#define __GAME_H__
#include<stdio.h>

#define ROW 3
#define COL 3

void InitBoard(char arr[ROW][COL],int row, int col);
void DisplayBoard(char arr[ROW][COL],int row, int col);
void PlayerMove(char arr[ROW][COL],int row, int col);
void ComputerMove(char arr[ROW][COL],int row, int col);
char IsWin(char arr[ROW][COL],int row, int col);


#endif  //__GAME_H__