C语言实现小游戏三字棋

目录

一、 摘要

二、 文件配置

三、 功能实现

1 开始游戏界面

2 游戏内容game()

2.1 初始化棋盘为空格

2.2打印棋盘

2.3 玩家下棋以及电脑下棋

2.4 判断输赢

四、游戏代码


一、 摘要

  学习了C语言的分支结构、循环结构、数组、函数后,我们将知识融会贯通来实现一个三字棋小游戏吧。

二、 文件配置

   好的代码习惯从C语言就开始,以后我们到公司做项目的时候,需要维护自己的代码段,所以我们今天的代码就分别放在三个文件:test.c、game.c、game.h中。test.c源文件主要用来测试整个小游戏;game.c源文件主要用来完成小游戏各功能的实现;game.h头文件中则用来包含所有的库函数并声明game.c中的函数。这样一来,代码的可读性提高了,同时方便后期调试与维护。

三、 功能实现

  我们先一步步展示各功能,最后展示整个项目:

1 开始游戏界面

void menu()
{
	printf("********************************\n");
	printf("*********  1. play  ************\n");
	printf("*********  0. exit  ************\n");
	printf("********************************\n");
}
int main()
{
    int input = 0;
	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;
}

  我们定义了一个菜单函数,同时在主函数里开始运行,运用switch语句,输入1则进入游戏,输入0则退出游戏,输入其他数字则重新输入,同时我们想:玩一把不过瘾想要继续玩怎么办?用循环结构就好了,我们选择do-while语句先执行后判断,由input控制循环,如果选择了0那正好不符合while的条件退出循环

C语言实现小游戏三字棋_第1张图片

2 游戏内容game()

#define ROW 3
#define COL 3
void game()
{
	char board[ROW][COL] = { 0 };
    //初始化棋盘
    Initboard(board,ROW,COL);
    //打印棋盘
    Displayboard(board,ROW,COL);
}

  玩三字棋,棋盘首先是空的,而且要打印出来让玩家看到,那么我们就需要先实现初始化棋盘打印棋盘。棋盘是3*3的,所以我们很容易想到用二维数组来定义棋盘:board[3][3]

  我们用宏定义常量ROW(行)为3,定义常量COL(列)也为3,这样方便后续程序升级为五子棋等更大棋盘的游戏

2.1 初始化棋盘为空格

void Initboard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

2.2打印棋盘

C语言实现小游戏三字棋_第2张图片

我们想打印一个这样的棋盘,行列间都有间隔,看起来舒服。

void Displayboard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		//打印分割线___
		if (i < row)
		{
			for (int j = 0; j < col; j++)
			{
				printf("___");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

 C语言实现小游戏三字棋_第3张图片

2.3 玩家下棋以及电脑下棋

玩家下棋和电脑下棋的顺序可以在game函数里设置,这边分别实现两个函数玩家下棋和电脑下棋:

1)玩家下棋(*)

玩家下棋只需要在二维数组board[3][3]中设置值即可,我们让玩家输入下棋的坐标x和y分别表示第x行和第x列。

玩家下棋必须在限定的棋盘范围内下棋,三字棋的棋盘为3*3,二维数组中行和列下标是从0-2,那么为了玩家着想,玩家输入的x和y的范围是1-3,那么程序里就让board[x-1][y-1]='*' ,正确下完这步棋就退出循环,否则提示重新落子

正确落子的两个判定:

格子里没下过棋,即board[x-1][y-1]= ' '

落子的范围在棋盘内,即1<= x,y <= ROW,COL 

void Playermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋\n");
	while (1)
	{
		printf("输入坐标x y,请落子:>\n");
		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");
	}
}

2)电脑下棋(#)

电脑随机下棋,即电脑输入的坐标x和y是随机的,那么我们要运用到生成随机数的三个函数:

int rand(void)           void srand(unsigned int seed)         time_t time(time_t* timer)

#include
#include

srand((unsigned int)time(NULL));
x=rand()%ROW;
y=rand()%COL;

rand函数会在0-32787中随机生成一个值,虽然每次调用的值随机,但是每次调试程序的值是固定的,也就是第一把电脑怎么落子,后面几把电脑也怎么落子,没有做到完全随机

rand函数每次都会调用srand函数,让srand函数为其确定随机数的起始值,而srand函数的接收类型是unsigned int类型,所以srand函数如果接收一个固定的值,比如srand(1)、srand(243)等,会让rand函数每次都生成固定的随机数,这也是为什么如果rand函数没有做到完全随机的原因。所以我们要人为地让srand函数接收不同的数,达到rand函数每次都生成随机数的目的。

这时就用到time函数,时间是时刻变化的,time函数接收time_t类型的指针(可以是空指针NULL),返回的类型time_t,而srand函数的接收类型是unsigned int,所以我们用一个强制类型转换,并设置time的接收是空指针NULL即可。

x=rand()%ROW的意思是每次电脑输入的x坐标在0 - ROW-1的范围内

y=rand()%COL的意思是每次电脑输入的y坐标在0 - COL-1的范围内

完成了随机下棋的实现,剩下的步骤和玩家下棋是一致的,只不过电脑是不需要提示越界或者会落在下过棋的地方

void Computermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
    srand((unsigned int)time(NULL));
	printf("电脑下棋:>\n");
	while (1)
	{
		x = rand() % row;//x的范围在0-row-1
		y = rand() % col;//y的范围在0-col-1
		if (board[x][y] == ' ')//没下过棋的地方
		{
			board[x][y] = '#';
			break;
		}
	}
}

完善一下game函数:

void game()
{
	char board[ROW][COL] = { 0 };

    //打印棋盘
	Initboard(board,ROW,COL);
	//下棋
	Displayboard(board,ROW,COL);

	while (1)
	{
		//玩家先下
		Playermove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		//判断输赢,出结果就break
        break;
		//电脑后下
		Computermove(board, ROW, COL);
		Displayboard(board, ROW, COL);
	    //判断输赢,出结果就break
        break;
	}
    //判断哪方赢
}

玩家先下或者电脑先下可以由我们人为设置,玩家下完或者电脑下完都判断一下是否出结果,出结果然后跳出循环,然后在循环外判断哪方赢,于是我们继续实现一下判断的部分。

2.4 判断输赢

C语言阶段我们做过的判断函数包括判断素数、判断闰年函数等,返回类型一般设为int,返回值一般为1或者0。我们可以采用同样的思路,对不同的结果返回不同的值。一把三字棋结束的条件有三种:玩家赢、电脑赢或者平局,如果没结束那就继续下棋,一共是四个判断。

我们将函数的返回类型设为char:

玩家赢,返回值设为: '*'

电脑赢,返回值设为:'#'

平局,返回值设为:'Q'

继续,返回值设为:'C'

1)三行中其中一行均是*号或者#号

for (int 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];
		}
	}

注:如果满足if语句,说明有一方赢了,玩家赢则返回'*',电脑赢则返回'#',那直接返回二维数组的值即可

2)三列中其中一列均是*号或者#号

for (int i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
		}
	}

3)对角线均是*号或者#号

//左对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') 
	{
		return board[0][0];
	}
//右对角线	
else if ((board[0][2] == board[1][1] && board[1][1] == board[2][0] && 
board[0][2] != ' '))
	{
		return board[0][2];
	}

4)平局判断棋盘是否已经下满了

int Isfull(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;//下满了
}

if (Isfull(board, col, row) == 1)
{
	return 'Q';
}

整合成判断输赢函数:

char Iswin(char board[ROW][COL], int row, int col)
{
	
//行赢
	for (int 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 (int i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] 
&& board[0][i] != ' ')
		{
			return board[0][i];
		}
	}
	

//对角线赢
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] 
&& board[0][0] != ' ') 
	{
		return board[0][0];
	}
	else if ((board[0][2] == board[1][1] && board[1][1] == board[2][0] 
&& board[0][2] != ' '))
	{
		return board[0][2];
	}
	

//平局
	if (Isfull(board, col, row) == 1)
	{
		return 'Q';
	}
	

//继续
	return 'C';
}

将判断输赢函数放入游戏主体函数game中:

void game()
{
	char board[ROW][COL] = { 0 };
	char ret = 0;
	Initboard(board,ROW,COL);
	//打印棋盘
	Displayboard(board,ROW,COL);
	//下棋
	while (1)
	{
		//玩家先下
		Playermove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		//判断输赢
		ret = Iswin(board, ROW, COL);
		if (ret != 'C')//ret等于C时继续游戏
			break;
		//电脑后下
		Computermove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		//判断输赢
		ret = Iswin(board, ROW, COL);
		if (ret != 'C')//ret等于C时继续游戏
			break;
	}
	if (ret == '*')
		printf("玩家赢了\n");
	else if (ret == '#')
		printf("电脑赢了\n");
	else if(ret == 'Q')
		printf("平局\n");
}

四、游戏代码

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 };
	char ret = 0;
	Initboard(board,ROW,COL);
	//打印棋盘
	Displayboard(board,ROW,COL);
	//下棋
	while (1)
	{
		//玩家先下
		Playermove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		//判断输赢
		ret = Iswin(board, ROW, COL);
		if (ret != 'C')//ret等于C时继续游戏
			break;
		//电脑后下
		Computermove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		//判断输赢
		ret = Iswin(board, ROW, COL);
		if (ret != 'C')//ret等于C时继续游戏
			break;
	}
	if (ret == '*')
		printf("玩家赢了\n");
	else if (ret == '#')
		printf("电脑赢了\n");
	else if(ret == 'Q')
		printf("平局\n");
}
int main()
{
	int input = 0;
	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.c:

#include "game.h"

//初始化棋盘为空格
void Initboard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

//打印棋盘
void Displayboard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		//打印分割线
		if (i < row)
		{
			for (int j = 0; j < col; j++)
			{
				printf("___");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

//玩家下棋
void Playermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋\n");
	while (1)
	{
		printf("输入坐标x y,请落子:>\n");
		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 Computermove(char board[ROW][COL], int row, int col)
{
	srand((unsigned int)time(NULL));
	int x = 0;
	int y = 0;
	printf("电脑下棋:>\n");
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - 'C'
char Iswin(char board[ROW][COL], int row, int col)
{
	
//行赢
	for (int 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 (int i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] 
&& board[0][i] != ' ')
		{
			return board[0][i];
		}
	}
	

//对角线赢
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] 
&& board[0][0] != ' ') 
	{
		return board[0][0];
	}
	else if ((board[0][2] == board[1][1] && board[1][1] == board[2][0] 
&& board[0][2] != ' '))
	{
		return board[0][2];
	}
	

//平局
	if (Isfull(board, col, row) == 1)
	{
		return 'Q';
	}
	

//继续
	return 'C';
}

game.h:

#pragma once
#include
#include
#include
#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 Playermove(char board[ROW][COL], int row, int col);
//电脑下棋
void Computermove(char board[ROW][COL], int row, int col);
//判断输赢
char Iswin(char board[ROW][COL], int row, int col);
//平局判断棋盘是否满
int Isfull(char board[ROW][COL], int row, int col);

你可能感兴趣的:(c语言)