C语言井字棋游戏

目录

1.头文件game.h

2.源文件

2.1主函数

2.2子函数

3.程序的不足

1.头文件game.h

        可取点:在头文件中,使用#define定义行和列类,在后续的程序中行和列没有具体数值,全部通过ROW和COL表示。这样以后想要对棋盘的大小进行修改的时候,直接在头文件中对#define进行修改即可。

#define ROW 3
#define COL 3

#pragma once  #define ROW 3 #define COL 3  #include  //菜单函数 void menu(); //是否继续游戏菜单 void ContinueMenu(); //游戏函数 void game(); //初始化棋盘 void InitBoard(char Board[ROW][COL], int row, int col); //展示棋盘 void DisplayBoard(char Board[ROW][COL], int row, int col); //玩家下棋 void PlayerMove(char Board[ROW][COL], int row, int col); //电脑下棋 void ComputerMove(char Board[ROW][COL], int row, int col); //判断胜、负或平局 char Judge(char Board[ROW][COL], int row, int col); //判断棋盘是否下满了 int Full(char Board[ROW][COL], int row, int col);

2.源文件

2.1主函数

//井字棋游戏 #include"game.h"  int main() { 	int input = 0; 	int con = 0; 	do 	{ 		menu(); 		printf("请选择:"); 		scanf("%d", &input); 		switch (input) 		{ 		case 1: 			printf("开始游戏\n"); 			game(); 			ContinueMenu(); 			printf("请选择:"); 			scanf("%d", &con); 			break; 		case 2: 			printf("退出游戏\n"); 			break; 		default: 			printf("输入无效,请重新选择\n"); 			break; 		} 	} 	while (con == 1 ||(input != 2 && input != 1)); 	return 0; }

2.2子函数

要点

       1. 子函数【2.2棋盘生成函数】,生成的棋盘样式如下图,不知道这样直观的展示出来,会方便理解该程序吗?

        2.子函数【2.3玩家下棋函数】中

        因为数组的起始位置为[0][0],但大众一般认为的起始位置为[1][1],所以要进行+1、-1调整,以符合大众的认知。
        if ((i > 0 && i < row+1 && j > 0 && j < col+1) && (Board[i-1][j-1] == ' '))
        {
            Board[i-1][j-1] = 'O';
           ...

        如果输入的坐标无效,就要重新输入,为此设置了一个标志flag。如果flog=0,说明输入的坐标无效(位置被占用或超出棋盘范围),需要重新输入。

        3.生成随机数

        利用时间戳生成随机数,需要的头文件为#include和#include,使用rand()函数生成随机数之前,需要先使用srand()函数,生成随机数种子。

#include  #include  int ran;  srand((unsigned int)time(NULL));  ran = rand();

        4.【2.5判断胜负函数】

        如果是玩家胜利,就返回玩家使用的符号‘O’

        如果是电脑胜利,就返回电脑使用的符号‘X’

        如果是棋盘满了且未分出胜负,就返回‘E’

        如果以上三种情况都不是,就返回'C',继续进行游戏

#define ROW 3 #define COL 3 #include #include #include  //1.菜单函数 void menu() { 	printf("************************\n"); 	printf("*****1.Play  2.Exit*****\n"); 	printf("************************\n"); }   //2.游戏函数 void game() { 	char result; 	//生成棋盘 	char Board[ROW][COL] = { 0 }; 	//初始化棋盘 	InitBoard(Board, ROW, COL); 	//展示棋盘 	DisplayBoard(Board, ROW, COL); 	while (1) 	{ 		//玩家下棋 		PlayerMove(Board, ROW, COL); 		DisplayBoard(Board, ROW, COL); 		//判断胜负 		result = Judge(Board, ROW, COL); 			if (result != 'C') 		{ 			break; 		} 		//电脑下棋 		ComputerMove(Board, ROW, COL); 		DisplayBoard(Board, ROW, COL); 		//判断胜负 		result = Judge(Board, ROW, COL); 		if (result != 'C') 		{ 			break; 		} 	} 	if (result == 'O') 		printf("玩家获胜\n"); 	else if (result == 'X') 		printf("电脑获胜\n"); 	else 		printf("平局\n"); }   //2.1棋盘初始化函数 void InitBoard(char Board[ROW][COL],int row,int col) { 	int i, j; 	for (i = 0; i < row; i++) 	{ 		for (j = 0; j < col; j++) 		{ 			Board[i][j] = ' '; 		} 	} }  //2.2棋盘生成函数 void DisplayBoard(char Board[ROW][COL], int row, int col) { 	int i, j; 	for (i = 0; i < row; i++) 	{ 		for (j = 0; j < col; j++) 		{ 			//1.打印一行数据 			printf(" %c ", Board[i][j]); 			if (j < col - 1) 				printf("|"); 		} 		printf("\n"); 		//2.打印分割线 		if (i < row - 1) 		{ 			for (j = 0; j < col; j++) 			{ 				printf("---"); 				if (j < col - 1) 				printf("|"); 			} 			printf("\n"); 		} 	} }  //2.3玩家下棋 void PlayerMove(char Board[ROW][COL], int row, int col) { 	int i, j; 	int flag = 1; 	printf("玩家回合\n"); 	do  	{ 		printf("请输入坐标:"); 		scanf("%d%d", &i, &j);         //因为数组的起始位置为[0][0],但大众一般认为的起始位置为[1][1],所以要进行+1、-1调整 		if ((i > 0 && i < row+1 && j > 0 && j < col+1) && (Board[i-1][j-1] == ' ')) 		{ 			Board[i-1][j-1] = 'O'; 			flag = 1; 		} 		else 		{             //如果输入的坐标无效,就要重新输入,为此设置了一个标志flag 			printf("坐标无效,请重新输入\n"); 			flag = 0; 		} 	} 	while (flag == 0); }  //2.4电脑下棋 void ComputerMove(char Board[ROW][COL], int row, int col) { 	int i, j; 	int flag = 1; 	printf("电脑回合\n"); 	do  	{ 		//通过时间生成随机位置 		srand((unsigned int)time(NULL));         //通过模row取余数,就能让i在0~row-1之间浮动;j同理 		i = rand() % row; 		j = rand() % col; 		if (Board[i][j] == ' ') 		{ 			Board[i][j] = 'X'; 			flag = 1; 		} 		else 			flag = 0; 	} 	while (flag == 0); }  //2.5判断胜负函数 char Judge(char Board[ROW][COL], int row, int col) { 	int i, j; 	//判断行是否连成三个 	for (i = 0; i < row; i++) 	{ 		int count = 0; 		for (j = 0; j < col-1; j++) 		{ 			if ((Board[i][0] != ' ') && (Board[i][j] == Board[i][j + 1])) 			{ 				count++; 			} 		} 		if (col-1 == count) 			return Board[i][0]; 	} 	//判断列是否连成三个 	for (j = 0; j < col; j++) 	{ 		int count = 0; 		for (i = 0; i < row-1; i++) 		{ 			if ((Board[0][j] != ' ') && (Board[i][j] == Board[i+1][j])) 			{ 				count++; 			} 		}         //三个元素相等,计数器的数字应该比行数少1。可以用两刀切三段理解。 		if (row - 1 == count) 			return Board[0][j]; 	} 	//判断斜线是否连成三个 	if (Board[0][0] == Board[1][1] && Board[2][2] == Board[1][1] && Board[0][0] != ' ') 	return Board[0][0]; 	if (Board[0][2] == Board[1][1] && Board[2][0] == Board[1][1] && Board[0][2] != ' ') 	return Board[0][2]; 	//判断是否平局 	if (1 == Full(Board, ROW, COL)) 	{ 		return 'E'; 	} 	return 'C'; }  //2.5.1判断棋盘是否满了函数 int Full(char Board[ROW][COL], int row, int col) { 	int i, j; 	for (i = 0; i < row; i++) 	{ 		for (j = 0; j < col; j++) 		{ 			if (Board[i][j] == ' ') 				return 0; 		} 	} 	return 1; }    //3.继续游戏函数 void ContinueMenu() { 	printf("************************\n"); 	printf("游戏已结束,是否继续游戏\n"); 	printf("***1.Continue  2.Exit***\n"); 	printf("************************\n"); }  

3.程序的不足

        程序的不足出现在子函数【2.4电脑下棋】函数中。在实际游玩的发现,在游戏的后期,电脑下棋的速度会变慢。我分析原因如下:

        1.电脑下棋的位置完全靠随机数生成,这就导致在游玩的后期,当大多数格子被占用时,电脑往往需要进行多次循环,才能随机出新的位置,耗费计算资源。

        2.完全随机的落子,也导致电脑下棋没什么策略性,导致玩家很容易胜利,游戏的趣味性降低。  

        如果大家有好的解决方案,欢迎留言!

//2.4电脑下棋 void ComputerMove(char Board[ROW][COL], int row, int col) { 	int i, j; 	int flag = 1; 	printf("电脑回合\n"); 	do  	{ 		//通过时间生成随机位置 		srand((unsigned int)time(NULL));         //通过模row取余数,就能让i在0~row-1之间浮动;j同理 		i = rand() % row; 		j = rand() % col; 		if (Board[i][j] == ' ') 		{ 			Board[i][j] = 'X'; 			flag = 1; 		} 		else 			flag = 0; 	} 	while (flag == 0); }