“纯C”实现——三子棋小游戏

在这里插入图片描述

文章目录

⚡text.c文件
⚡game.c文件
⚡game.h


⚓三子棋实现思路

三子棋游戏就是玩家和电脑之间轮流下棋,首先它的棋盘为3X3,我们玩家先下棋,然后到电脑,只要其中一方下的棋子连成了一条线即为胜利。 那么要实现游戏的前提首先是得有一个棋盘显示出来,然后把我们每一次下的棋到显示在屏幕上直到一方胜利或者和局。所以

我们第一步是要打印棋盘:

打印棋盘的前提是有数据可以打印,所以我们需要用到一个3X3的二维数组,刚开始里面没有数据,我们先初始化成空格,这样打印出来就是空白的形式,为了方便区分玩家和电脑下棋,我们可以规定
玩家下棋就用符号" *“填补
电脑下棋就用符号”# "填补

那么第二步:

棋盘打印出来屏幕后,就是玩家下棋,那么我们需要一个玩家下棋的独立函数,用来接收玩家输入的坐标,而且要判断坐标是否合法

第三步:

玩家下完棋后,就是电脑下棋,电脑下棋我们可以用随机值进行下棋
此时我们又可以实现一个电脑下棋的独立函数

第四步:

玩家和电脑每下一次棋,我们都需要判断一下是否有一方已经胜利了,或者棋盘是否满了,所以我们又需要一个独立函数用来判断

第五步:

把上述的所有函数用循环连接起来即可,下面直接看我操作
在这里插入图片描述

在这里插入图片描述

⚓棋盘实现

下面的图就是我们要实现的棋盘,首先要创建一个3X3的二维数组

#define ROW 3		//行
#define COL 3		//列
char board[ROW][COL]

我们用宏定义来定义行列,方便以后要打印成其他4X4,10X10的棋盘
而且我们要把它初始化成空格

//初始化成空格
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] = ' ';
		}
	}
}

可以看一个下的棋下面都有三个“-”符号,因为我们的“ # ”,和“ * ”都只占一个位置,所以我们打印的时候要用空格隔开
在这里插入图片描述
用宏定义的好处,如果把ROW和COL改成10,那么它可以直接打印成下面的10X10格子 注意我们下面是基于3X3格子进行实现的三子棋,只适用于3x3格子
在这里插入图片描述
下面我们就实现一下打印棋盘的代码
实现代码:

//打印棋盘
void BoardPrint(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");
		for (j = 0; j < col; j++)
		{
    
    
			printf("---");
			//这里跟上面用一个意思
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
	}
}

⚓玩家下棋

玩家下棋的方式是输入坐标 ,所以需要接收玩家输入的数据,我们要考虑到

**用户友好性**

因为我们使用的是二维数组,下标都是从0开始的,而玩家不一定是程序员,是不知道的这件事的,所以用户输入的数据时要注意处理

在这里插入图片描述
处理用户输入的数据只需将它-1即可,
比如玩家输入坐标"3 3",在后台改变数组的时候就将它减1变成“2 2”
同时还有判断当前坐标是否已经被占用了,如果被占用了还需要提醒玩家重新输入,直到输入正确为止,所以我们要使用到循环结构 坐标没有被占用,我们就可以将数组对应的位置放字符“ * ”

void PlayerMove(char board[ROW][COL], int row, int col)
{
    
    
	while (1)
	{
    
    
		printf("请输入坐标>:");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		//判断坐标是否合法
		if (x <= 3 && x > 0 && y <= 3 && y > 0)
		{
    
    
			if (board[x - 1][y - 1] == ' ')
			{
    
    
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
    
    
				printf("坐标被占用,不能下棋,请选择其他位置\n");
			}
		}
		else
		{
    
    
			printf("坐标非法,请重新输入\n");
		}
	}
}

⚓电脑下棋

电脑下棋使用rand函数获取随机值,将它坐标按行和列取模,比如随机值是100,那么取模行row之后,就为1,
电脑下棋就不用判断坐标是否合法了,只需要确定它取模后的数字范围在0~2之间即可
还需要注意获取的坐标是否被占用即可

因为我们是使用随机值的方式让电脑下棋,使用这样的方式下棋,电脑是很“笨”的,不会对我们下的棋进行拦截,简而言之就是不够“智能”,当然如果, 你感兴趣的话,可以对它进行一些算法处理,比如穷举一些玩家可能性下的棋,对它进行预判等等,让它变得更加“智能”一些,但本文章就不做优化了,留给你们自行处理!

//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
    
    
	while (1)
	{
    
    
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
    
    
			board[x][y] = '#';
			break;
		}
	}
}

在这里插入图片描述

⚓判断输赢

判断输赢大概就以下几种,我们可以使用枚举的方式,也可以使用循环的方式去判断,下面我给出两个版本,一个是枚举的,一个是循环的

我们规定玩家赢返回“ * ”,电脑赢返回“ # ”,平局返回“Q”,进行游戏返回“0”

在这里插入图片描述
枚举

//版本1.0枚举
//玩家赢返回"*",电脑赢返回""#,棋盘满了返回"Q"
char  DetermineEnd1(char board[ROW][COL])
{
    
    
	//玩家赢的情况
	if ((board[0][0] == board[0][1]  && board[0][1] == board[0][2]&&board[0][0]=='*')
		|| (board[1][0] == board[1][1]  && board[1][1] == board[1][2] && board[1][0] == '*')
		|| (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '*')
		|| (board[0][0] == board[1][0]  && board[1][0] == board[2][0]&&board[0][0] == '*')
		|| (board[0][1] == board[1][1]  && board[1][1] == board[2][1] && board[0][1] == '*')
		|| (board[0][2] == board[1][2]  && board[1][2] == board[2][2] && board[0][2] == '*')
		|| (board[0][0] == board[1][1]  && board[1][1] == board[2][2] && board[0][0] == '*')
		|| (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] == '*'))
	{
    
    
		
		return '*';
	}
	//电脑赢的情况
	else if ((board[0][0] == board[0][1] && board[0][1] == board[0][2]&&board[0][0]=='#')
		|| (board[1][0] == board[1][1] && board[1][1] == board[1][2] && board[1][0] == '#')
		|| (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '#')
		|| (board[0][0] == board[1][0]  && board[1][0] == board[2][0]&&board[0][0] == '#')
		|| (board[0][1] == board[1][1] && board[1][1] == board[2][1] && board[0][1] == '#')
		|| (board[0][2] == board[1][2] && board[1][2] == board[2][2] && board[0][2] == '#')
		|| (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] == '#')
		|| (board[0][2] == board[1][1]  && board[1][1] == board[2][0] && board[0][02] == '#'))
	{
    
    
		
		return '#';
	}
	else
	{
    
    
		//判断棋盘是否满了
		for (int i = 0; i < ROW; i++)
		{
    
    
			for (int j = 0; j < COL; j++)
			{
    
    
				if (board[i][j] == ' ')
					return '0';
			}
		}
	}
	//程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
	return 'Q';
}
其实循环和枚举在这里都是大同小异。

循环

//版本2.0循环
// 判断游戏是否结束     玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char  DetermineEnd2(char board[ROW][COL], int row, int col)
{
    
    
	int i = 0;
	//判断行
	for (i = 0; i < row; i++)
	{
    
    
		if ((board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' '))
		{
    
    
			return board[i][1];
		}
	}
	//判断列
	for (i = 0; i < row; i++)
	{
    
    
		if ((board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '))
		{
    
    
			return board[1][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];
	}
	//判断棋盘是否满了
	for (int i = 0; i < ROW; i++)
	{
    
    
		for (int j = 0; j < COL; j++)
		{
    
    
			//其中有一个空格就说明还没满,返回"0"
			if (board[i][j] == ' ')
				return '0';
		}
	}
	//程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
	return 'Q';
}

⚓小结语

其实不管是猜数字小游戏,还是前面实现的顺序表和单链表,看似代码很大,其实如果理解其中的思想,就知道他们都有一个共同点,都是一些基本操作组装起来。

接下来才是最关键的一步,就是将它们组装起来,形成一个可以运行的程序
我把它实现在text.c文件中。
在这里插入图片描述

⚡text.c文件

text.c为工程测试文件
#define _CRT_SECURE_NO_WARNINGS

#include"game.h"
void menu()
{
    
    
	printf("******************************\n");
	printf("******* 1. play    0. exit*****\n");
	printf("******************************\n");
}

void game()
{
    
    
	
	char board[ROW][COL] = {
    
     0 };
	//先初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘让玩家下棋
	BoardPrint(board, ROW, COL);
	char ret;
	while (1)
	{
    
    
		printf("玩家下棋\n");
		PlayerMove(board, ROW, COL);
		ret= DetermineEnd2(board,ROW,COL);
		if (ret != '0')
		{
    
    
			break;
		}
		BoardPrint(board, ROW, COL);
		printf("电脑下棋\n");
		ComputerMove(board, ROW, COL);
		ret = DetermineEnd2(board, ROW, COL);
		if (ret != '0')
		{
    
    
			break;
		}
		BoardPrint(board, ROW, COL);
	}
	if (ret == '*')
	{
    
    
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
    
    
		printf("电脑赢\n");
	}
	else
	{
    
    
		printf("平局\n");
	}
	BoardPrint(board, ROW, COL);

}
int main()
{
    
    
	//初始化随机值
	srand((unsigned int)time(NULL));
	//接收用户选择开始游戏,或者退出游戏的变量
	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文件

game.c为工程函数实现文件
#define _CRT_SECURE_NO_WARNINGS

#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 BoardPrint(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");
		for (j = 0; j < col; j++)
		{
    
    
			printf("---");
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
	}
}


void PlayerMove(char board[ROW][COL], int row, int col)
{
    
    
	while (1)
	{
    
    
		printf("请输入坐标>:");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		//判断坐标是否合法
		if (x <= 3 && x > 0 && y <= 3 && y > 0)
		{
    
    
			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)
{
    
    
	while (1)
	{
    
    
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
    
    
			board[x][y] = '#';
			break;
		}
	}
//}
版本1.0
玩家赢返回"*",电脑赢返回""#,棋盘满了返回"Q"
//char  DetermineEnd1(char board[ROW][COL])
//{
    
    
//	//玩家赢的情况
//	if ((board[0][0] == board[0][1]  && board[0][1] == board[0][2]&&board[0][0]=='*')
//		|| (board[1][0] == board[1][1]  && board[1][1] == board[1][2] && board[1][0] == '*')
//		|| (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '*')
//		|| (board[0][0] == board[1][0]  && board[1][0] == board[2][0]&&board[0][0] == '*')
//		|| (board[0][1] == board[1][1]  && board[1][1] == board[2][1] && board[0][1] == '*')
//		|| (board[0][2] == board[1][2]  && board[1][2] == board[2][2] && board[0][2] == '*')
//		|| (board[0][0] == board[1][1]  && board[1][1] == board[2][2] && board[0][0] == '*')
//		|| (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] == '*'))
//	{
    
    
//		
//		return '*';
//	}
//	//电脑赢的情况
//	else if ((board[0][0] == board[0][1] && board[0][1] == board[0][2]&&board[0][0]=='#')
//		|| (board[1][0] == board[1][1] && board[1][1] == board[1][2] && board[1][0] == '#')
//		|| (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '#')
//		|| (board[0][0] == board[1][0]  && board[1][0] == board[2][0]&&board[0][0] == '#')
//		|| (board[0][1] == board[1][1] && board[1][1] == board[2][1] && board[0][1] == '#')
//		|| (board[0][2] == board[1][2] && board[1][2] == board[2][2] && board[0][2] == '#')
//		|| (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] == '#')
//		|| (board[0][2] == board[1][1]  && board[1][1] == board[2][0] && board[0][02] == '#'))
//	{
    
    
//		
//		return '#';
//	}
//	else
//	{
    
    
//		//判断棋盘是否满了
//		for (int i = 0; i < ROW; i++)
//		{
    
    
//			for (int j = 0; j < COL; j++)
//			{
    
    
//				if (board[i][j] == ' ')
//					return '0';
//			}
//		}
//	}
//	//程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
//	return 'Q';
//}

//版本2.0
// 判断游戏是否结束     玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char  DetermineEnd2(char board[ROW][COL], int row, int col)
{
    
    
	int i = 0;
	//判断行
	for (i = 0; i < row; i++)
	{
    
    
		if ((board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' '))
		{
    
    
			return board[i][1];
		}
	}
	//判断列
	for (i = 0; i < row; i++)
	{
    
    
		if ((board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '))
		{
    
    
			return board[1][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];
	}
	//判断棋盘是否满了
	for (int i = 0; i < ROW; i++)
	{
    
    
		for (int j = 0; j < COL; j++)
		{
    
    
			//其中有一个空格就说明还没满,返回"0"
			if (board[i][j] == ' ')
				return '0';
		}
	}
	//程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
	return 'Q';
}


⚡game.h

game.h为工程的函数和变量声明的头文件
#pragma once

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

#define ROW 3		//行
#define COL 3		//列

//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘
void BoardPrint(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);

//  版本1.0     判断游戏是否结束     玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char  DetermineEnd1(char board[ROW][COL]);


//版本2.0    判断游戏是否结束     玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char  DetermineEnd2(char board[ROW][COL],int row,int col);




不要让舒适夺走了你本可以拥有的东西!!

猜你喜欢

转载自blog.csdn.net/dongming8886/article/details/124503153