C语言基础之——三子棋(详解)

前言:文章最后将给出完整代码,前边的代码会因为便于讲解而不全面,仅供参考。

目录

一.三子棋游戏规则

二.分析如何布局

三.代码展示与讲解

1.游戏菜单

2.展示棋盘

3.玩家下棋

4.电脑下棋

5.判断输赢/平局

四.全代码展示

1.game.h

2.game.c

3.test.c

五.总结


一.三子棋游戏规则

       朋友们小时候肯定都玩过三子棋,无非就是一个三乘三的棋盘,两个人轮流落子,谁的棋子率先连成一排一列一个对角线就会胜出,但是这个游戏也会出现无子可落,也就是九个格子被占满了,造成平局

二.分析如何布局

       我们知道,写代码讲究一个整洁有序,即使是设计三子棋这样一个极为简单的游戏,也不是短短几十行代码就能搞定的。

       如下图,我们通过创建一个自己的头文件"game.h"来集中存放我们需要使用到的头文件,以及声明我们需要用到的函数,只需要在源文件中都要声明我们自己的头文件#include"game.h"即可。

 

此外,我们又创建一个新的源文件game.c来集中创建我们需要的函数。

 最后,我们游戏的主体代码则写在源文件test.c中。

三.代码展示与讲解

1.游戏菜单

任何游戏都需要一个菜单来选择游戏如何进行。

void menu()//打印菜单函数
{
	printf("******************************\n");
	printf("*******     1.play     *******\n");
	printf("*******     0.exit     *******\n");
	printf("******************************\n");

}
char board[ROW][COL] = {'0'};//游戏数组
int main()
{
	int input = 0;
	do {
		menu();
		printf("请选择->:");
		scanf("%d", &input);//选择
		switch (input)
		{
		case 1:
			printf("三子棋\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

         我们创建一个menu(菜单)函数来专门输出我们的菜单,并通过do-while循环switch-case语句来实现游戏的循环游玩。

       这里有一个小技巧,我们知道while的判断条件是0为假非零为真,所以我们用case 0作为退出游戏,同时也能终止循环,而输入1其他数字,则会继续循环,重新选择。

2.展示棋盘

我们理想中的棋盘长这个样子,这很明显需要一个二维数组,而且这个二维数组的元素都为" ",(空格)

void SetBoard(char board[ROW][COL], int row, int col)//创建棋盘函数
{
	int i;
	int j;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}
void ShowBoard(char board[ROW][COL],int row,int col)//展示棋盘函数
{
	int i;
	int j;
	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)
		printf("---|---|---\n");
	}
}

       上边我们已经定义了数组char board[ROW][COL] = {'0'},将其定义为只有一个元素"0"的数组,之后我们通过上述第一个函数SetBoard来对棋盘进行创建,再通过ShowBoard函数对棋盘进行分格修饰并展示。

3.玩家下棋

void PlayerMove(char board[ROW][COL], int row, int col)//玩家下棋函数
{
	while (1)
	{
		printf("玩家下棋(选择坐标):");
		int x, y;
		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 3,我们只需让这两个数字都-1,便可达到效果。

4.电脑下棋

void ComputerMove(char board[ROW][COL], int row, int col)//电脑下棋函数
{
	printf("电脑下棋:\n");
	int x, y;
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
srand((unsigned int)time(NULL));//生成随机数,rand函数需要用,此处无用,供参考

电脑下棋的一个重点就是随机性,这里的坐标就要用到rand函数生成随机数了,注意电脑自己下棋就没有玩家那么多讲究了,生成的随机数在0-2之间即可,电脑下棋我们规定落子为'#'

5.判断输赢/平局

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

char IsWin(char board[ROW][COL], int row, int col) //判断输赢函数
{
	int i;
	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[0][i] != ' ')
			return board[0][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))//判断平局
	{
		return 'Q';
	}
	return 'C';
}

这里我们定义IsWin函数来判断输赢,并通过返回值来实现。

我们规定以下四种方式来判断游戏进程:

玩家赢-->返回 '*'
电脑赢-->返回 '#'
平局-->返回 'Q'
游戏继续-->返回 'C'

       为什么这样规定呢,我们知道玩家的棋子是'*',如果玩家赢了,那我们的某一行,一列,或者对角线都会是'*',这样我们随便返回一个元素,便可实现下边代码的玩家赢。电脑赢同理。同时我们也会出现平局的结果,那么如何才是平局呢?很简单,如果没有人获胜,并且棋盘已经填满,那不就代表着平局吗?

于是我们定义IsFull函数来判断数组是否填满,填满则返回1,这样最后的if判断语句为真,最终返回'Q',没填满则返回0,最终返回'C'

	char ret = 0;//判断结果
		case 1:
			SetBoard(board, ROW, COL);//创建棋盘
			ShowBoard(board, ROW, COL);//展示棋盘
			while (1)
			{
				//玩家先开始下棋
				PlayerMove(board, ROW, COL);
				ShowBoard(board, ROW, COL);//下棋之后展示棋盘
				//判断输赢
				ret = IsWin(board, ROW, COL);
				if (ret != 'C')
					break;
				//电脑开始下棋
				ComputerMove(board, ROW, COL);
				ShowBoard(board, ROW, COL);//下棋之后展示棋盘
				//判断输赢
				ret = IsWin(board, ROW, COL);
				if (ret != 'C')
					break;
			}
			if (ret == '*')
				printf("玩家赢\n");
			else if (ret == '#')
				printf("电脑赢\n");
			else
				printf("平局\n");
			break;

 此处为主函数判断,我们定义ret来接收IsWin函数的返回值,并通过if -else判断语句来实现判断游戏结果。

四.全代码展示

1.game.h

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3//行数为三
#define COL 3//列数为三
void SetBoard(char board[ROW][COL], int row, int col);//创建棋盘
void ShowBoard(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);//判断输赢

2.game.c

#include"game.h"
void SetBoard(char board[ROW][COL], int row, int col)//创建棋盘函数
{
	int i;
	int j;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}
void ShowBoard(char board[ROW][COL],int row,int col)//展示棋盘函数
{
	int i;
	int j;
	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)
		printf("---|---|---\n");
	}
}
void PlayerMove(char board[ROW][COL], int row, int col)//玩家下棋函数
{
	while (1)
	{
		printf("玩家下棋(选择坐标):");
		int x, y;
		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)//电脑下棋函数
{
	printf("电脑下棋:\n");
	int x, y;
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
//玩家赢-->'*'
//电脑赢-->'#'
//平局-->'Q'
//游戏继续-->'C'
int IsFull(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;
}

char IsWin(char board[ROW][COL], int row, int col) //判断输赢函数
{
	int i;
	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[0][i] != ' ')
			return board[0][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))//判断平局
	{
		return 'Q';
	}
	return 'C';
}

3.test.c

#include"game.h"
void menu()//打印菜单函数
{
	printf("******************************\n");
	printf("*******     1.play     *******\n");
	printf("*******     0.exit     *******\n");
	printf("******************************\n");

}
char board[ROW][COL] = {'0'};//游戏数组
int main()
{
	srand((unsigned int)time(NULL));//生成随机数,供电脑下棋使用
	int input = 0;
	char ret = 0;//判断结果
	do {
		menu();
		printf("请选择->:");
		scanf("%d", &input);//选择
		switch (input)
		{
		case 1:
			SetBoard(board, ROW, COL);//创建棋盘
			ShowBoard(board, ROW, COL);//展示棋盘
			while (1)
			{
				//玩家先开始下棋
				PlayerMove(board, ROW, COL);
				ShowBoard(board, ROW, COL);//下棋之后展示棋盘
				//判断输赢
				ret = IsWin(board, ROW, COL);
				if (ret != 'C')
					break;
				//电脑开始下棋
				ComputerMove(board, ROW, COL);
				ShowBoard(board, ROW, COL);//下棋之后展示棋盘
				//判断输赢
				ret = IsWin(board, ROW, COL);
				if (ret != 'C')
					break;
			}
			if (ret == '*')
				printf("玩家赢\n");
			else if (ret == '#')
				printf("电脑赢\n");
			else
				printf("平局\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

五.总结

       三子棋的创作大概就是这样了,博主也是初学者,很多地方可能会有更多的改进方案,今后将会在不断学习中提升自己来改进代码,同时也感谢朋友们能够耐心的看完我的讲解,如果有任何问题或者改进意见,欢迎各位私信评论。

       最后,希望我们喜欢编程的小伙伴们都能越走越远,都能拿到自己心仪的offer,喜欢博主文章的话不要忘记一键三连哦,我们下期再见!