c语言项目——实现三子棋(多子棋)

  大家好呀,我是心跳sy,今天给大家带来一个简单好玩的c语言小游戏——三子棋(多子棋),三子棋是一个可以对c语言基础知识进行系统复习回顾的小项目,建议初学c语言的宝子们都一定要自己多多尝试哦,今天给大家分享一下我实现的三子棋项目,有任何问题欢迎各位大佬指正支持哦~~嘻嘻。


  首先三子棋或者多子棋是一个n*n的棋盘,所以我们在写之前会联想到二维数组的构建,通过二维数组,确定棋盘的行和列,进而确定一系列函数,对二维数组进行初始化赋值、判断输赢、进行下棋、显示输出等功能,进而实现三子棋或者多子棋的构建。

  实现这个项目我们可以分三个文件进行,分别是test.c、game.c、game.h这三个文件,可以使我们的项目更加清楚明了,也可以更好地控制整个程序的运行。其中test.c文件中存放代码主体框架部分;game.c文件主要实现游戏地运行过程,包含有关游戏过程实现的所有函数定义;game.h包含宏定义行列、需要用到的库函数头文件以及各个函数的声明。下面代码按照分文件分模块进行实现:

 main函数主体部分

int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("开始游戏!\n");
			game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);
	return 0;
}

对 srand((unsigned int)time(NULL))的解释

  首先在主函数中srand((unsigned int)time(NULL))初始了随机函数种子 ,我们这里取时间作为随机种子,由于时间是不断变化的,所以可以产生不同的随机值,之后我们电脑下棋随机值的部署就是通过随机值生成器srand()生成时间种子再用rand()产生一个随机数。这里的unsigned int 是强制转换类型,意为将参数种子强制转换为无符号整型,通常我们用time(NULL)的返回值作为种子,来初始化rand()的起始值。

 对主体构架main函数的解释

  首先我们需要再循环之前就执行一次要不要进行游戏等一系列选择,所以我们采用do....while()循环,首先打印一个菜单menu(),对是否进行游戏进行选择,这里我们用scanf输入一个整数进行选择,用switch分支语句进行具体选择,若传入值为1则开始游戏,进入game()函数中,若为0则退出游戏,传入其他数值则重新进入循环选择。

下面开始实现game主体:

  首先定义一个字符型二维数组board,其中行和列由头文件中宏替换进行定义,这里我初始化行和列为3,我们同样也可改为5、10等等。

#define ROW 3
#define COL 3

分函数块实现game:

1、用InitBoard()函数初始化棋盘(将函数定义写在头文件处,以后函数皆是)

  开始将二维数组各个元素初始为空格

void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
	}
}

2、用DisplayBoard()函数打印棋盘  (之后玩家和电脑每下一次棋就可调用此函数打印结果)

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]);//注意为使数据居于中间,需在%c两边加空格
			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");
	}
}

  初始化打印的表格如下:(此为3*3的表格,若需修改为10*10则只需修改头文件中宏定义中的列和行)

 

3、用PlayerMove()函数实现玩家下棋

  这里的board[x - 1][y - 1],因为玩家输入的坐标不会像程序员们一样按照数组下标从0开始的规则,而是肉眼可见的行和列,于是电脑在判断时需要将x,y坐标各减一。

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:\n");
	while (1)
	{
		printf("请输入下棋坐标(中间用空格分开)如(1 1)\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");
		}
	}
}

 4、用ComputerMove()函数实现电脑下棋

  这里的x = rand() % row意为给x随机取一个0~row-1之间的随机整数,如x=rand()%3就是对3取余数,所得的x值就为0~2之间的随机整数,对y同理。

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋:\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % row;//产生随机值
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

 5、用IsWin()函数实现对输赢的判断

  此部分代码对游戏实现非常重要,我们需要分别判断行列,以及主对角线、副对角线元素是否相等,从而判定谁赢谁输,这里我们采用for循环以及if语句嵌套的方式进行判断,可以对任意设定的行和列数进行判断。我们规定:

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

char IsWin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int n = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;//计数器
		int r = 0;
		for (n = 0; n < col; n++)
		{
			if (board[i][n] == '*')
			{
				j++;
			}
			if (board[i][n] == '#')
			{
				r++;
			}
		}
		if (j == row)
		{
			return '*';
		}
		if (r == row)
		{
			return '#';
		}
	}
	for (i = 0; i < row; i++)
	{
		//清零
		int r = 0;
		int j = 0;
		for (n = 0; n < col; n++)
		{
			if (board[n][i] == '*')
			{
				r++;
			}
			if (board[n][i] == '#')
			{
				j++;
			}
		}
		if (r == col)
		{
			return '*';
		}
		if (j == col)
		{
			return '#';
		}
	}
	//判断正对角线
	int r = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (n = 0; n < col; n++)
		{
			if (i == n)
			{
				if (board[i][n] == '*')
				{
					r++;
				}
				if (board[i][n] == '#')
				{
					j++;
				}
			}
		}
	}
	if (r == row)
	{
		return '*';
	}
	if (j == row)
	{
		return '#';
	}
	//判断反对角线
	r = 0;
	j = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][row - 1 - i] == '*')
		{
			r++;
		}
		if (board[i][row - 1 - i] == '#')
		{
			j++;
		}
	}
	if (r == row)
	{
		return '*';
	}
	if (j == row)
	{
		return '#';
	}

	//判断平局
	if (IsFull(board, row, col))
	{
		return 'Q';
	}

	return 'C';
}

6、用IsFull()函数确定返回值来判断是否平局

此函数嵌套在IsWin()函数中最后一个if语句的判断条件中,用来判断是否为平局,若return 1则进入if语句中,返回“平局”。

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

分文件实现代码如下: 

test.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("**************************************\n");
	printf("**********请选择是否玩游戏:**********\n");
	printf("*************1.开始游戏***************\n");
	printf("*************0.退出游戏***************\n");
	printf("**************************************\n");

}
void game()
{
	char board[ROW][COL];
	int 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')
		{
			break;
		}
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("开始游戏!\n");
			game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);
	return 0;
}

 game.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(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++)
		{
			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 PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:\n");
	while (1)
	{
		printf("请输入下棋坐标(中间用空格分开)如(1 1)\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)
{
	printf("电脑下棋:\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
static int IsFull(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;
}
//玩家赢 - '*'
//电脑赢 - '#'
//平局 --- 'Q'
//游戏继续-'C'

char IsWin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int n = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;//计数器
		int r = 0;
		for (n = 0; n < col; n++)
		{
			if (board[i][n] == '*')
			{
				j++;
			}
			if (board[i][n] == '#')
			{
				r++;
			}
		}
		if (j == row)
		{
			return '*';
		}
		if (r == row)
		{
			return '#';
		}
	}
	for (i = 0; i < row; i++)
	{
		//清零
		int r = 0;
		int j = 0;
		for (n = 0; n < col; n++)
		{
			if (board[n][i] == '*')
			{
				r++;
			}
			if (board[n][i] == '#')
			{
				j++;
			}
		}
		if (r == col)
		{
			return '*';
		}
		if (j == col)
		{
			return '#';
		}
	}
	//判断正对角线
	int r = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (n = 0; n < col; n++)
		{
			if (i == n)
			{
				if (board[i][n] == '*')
				{
					r++;
				}
				if (board[i][n] == '#')
				{
					j++;
				}
			}
		}
	}
	if (r == row)
	{
		return '*';
	}
	if (j == row)
	{
		return '#';
	}
	//判断反对角线
	r = 0;
	j = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][row - 1 - i] == '*')
		{
			r++;
		}
		if (board[i][row - 1 - i] == '#')
		{
			j++;
		}
	}
	if (r == row)
	{
		return '*';
	}
	if (j == row)
	{
		return '#';
	}

	//判断平局
	if (IsFull(board, row, col))
	{
		return 'Q';
	}

	return 'C';
}

game.h文件

#pragma once
#include<stdio.h>
#include<time.h>
#define ROW 10
#define COL 10
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);

谢谢大家!感谢各位大佬们的阅读!本人编程小白一只,如有错误问题,欢迎友友们在评论区留言,欢迎各位大佬友友们指正哦!!!

 

猜你喜欢

转载自blog.csdn.net/m0_74475605/article/details/131926904