zl程序教程

您现在的位置是:首页 >  其他

当前栏目

三子棋小游戏————如何用C语言实现(含完整代码)

2023-03-07 09:43:15 时间

过程

https://live.csdn.net/v/embed/241852

QQ录屏20220925175438

整体思路(后面有思维导图,理清思维逻辑)

如何实现用C语言编写以上代码呢?其实并不难写,只是看起来比较繁琐罢了,但只要静下心来,把逻辑理顺,就能写出来,这对于新手小白来说是一个挑战,同时也是一个锻炼,那么如何能具体实现呢? 首先,我们为了能使自己的代码条理清晰,也方便自己以及他人日后查看,我们不能只写在一个源文件里,这样显得很繁琐。所以我们必须再创建一个源文件,用来存放被调用函数定义,同时,为了更加方便,我们再创建一个头文件,用来存放函数声明以及使用库函数时头文件的包含。然后在用来测试的源文件里着手写代码,首先要有一个菜单吧,供玩家选择,开始游戏,退出游戏等,然后我们要知道,我们最终的目的是在一个棋盘上进行游戏,既然是在棋盘上进行,就得有棋盘吧,所以我们要把一个棋盘用C语言写出来,写出来之后,我们还必须要有玩家和电脑来落子,否则怎么玩,既然落子,就会出现几种可能:1、玩家获胜。2、电脑获胜。3、平局(棋子满盘)。4、继续游戏(棋子未满盘)。

同时,我们可以把一个三子棋的棋盘看成是一个33的九宫格演变过来的,再仔细看,其实本质上是在一个二维数组里输入与#演变来的。知道这些,我们心里就有谱了,可以着手去写,完善细节。

实现过程

整理好之后开始入手:

#include"game.h"
//我们把函数声明,库函数头文件的包含都放在头文件game.h里,然后在测
//试源文件以及函数定义源文件里都包含一下,就可以实现跨文件使用

void menu()
{
	printf("************************************\n");
	printf("************************************\n");
	printf("*********     1、play     **********\n");
	printf("*********     0、exit     **********\n");
	printf("************************************\n");
	printf("************************************\n");
}

int main()
{
	int input = 0;
	//这是为了让电脑生成随机数使用的
	srand((unsigned int)time(NULL));

	do
	{
		//菜单
		menu();
		printf("请选择:>");
		scanf("%d", &input);

		//清理屏幕
		system("cls");
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("输入错误,请重新输入“:>\n");
			break;
		}

	} while (input);

	return 0;
}

这里实现了我们菜单栏的打印,以及整体的一个轮廓,到这里,我们已经把退出游戏,以及错误返回给写好了,下面就着重入手游戏环节,game()的实现。

void game()
{
	char ret = 0;
	//二维数组的创建
	char board[ROW][COL] = {0};

	//初始化棋盘
	init_board(board, ROW, COL);
	//打印棋盘
	display_board(board, ROW, COL);
	//玩游戏环节
	while (1)
	{
		//玩家下棋
		player_move(board, ROW, COL);
		//判断局面
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;

		}
		//打印棋盘

		display_board(board, ROW, COL);

		//电脑下棋
		computer_move(board, ROW, COL);
		//判断局面
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		//打印棋盘

		display_board(board, ROW, COL);

	}
	//我们自己规定,假如函数is_win(board, ROW, COL)返回值为*,表示玩家获胜
	//假如函数is_win(board, ROW, COL)返回值为#,表示电脑获胜
	//假如函数is_win(board, ROW, COL)返回值为C,表示继续游戏
	//假如函数is_win(board, ROW, COL)返回值为Q,表示平局



	if (ret == '*')
	{
		printf("-----------------------------------------------\n");
		printf("------------  !!!  VICTORY  !!!  --------------\n");
		printf("-----------------------------------------------\n");
		printf("----------- !!! 玩家获胜  !!! -----------\n");
		printf("-----------------------------------------------\n");

	}
	else if (ret == '#')
	{
		printf("-----------------------------------------------\n");
		printf("-------------  !!!  DEFEAT  !!!  --------------\n");
		printf("-----------------------------------------------\n");
		printf("----------- !!!  电脑获胜  !!! ----------\n");
		printf("-----------------------------------------------\n");

	}
	else if (ret == 'Q')
	{
		printf("--------------------------------------------\n");
		printf("---------------  !!!DRAW!!!  ---------------\n");
		printf("--------------------------------------------\n");
		printf("----------- !!!  平局  !!! -----------\n");
		printf("--------------------------------------------\n");
	}
}

注意,这里我用的是ROW与COL来表示数组的行与列,这是为了以后万一我们要调整棋盘行列数,只需要在头文件修改数据就可以了,避免了把程序写死(只能是33棋盘) 大家注意看我头文件的内容:

很清晰明了的就可以看到里面的内容,用#define定义常量,这里就是三行三列,假如想要55的棋盘,只需要在这里修改ROW与COL的值就可以,很灵活。就像这样:避免了写死程序。

接下来就是这些函数的具体内容了,跟着思维导图,先看一下游戏前的准备:

void init_board(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 display_board(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)//第col-1列不打印|
			{
				printf("|");
			}
		}
		//换行
		printf("\n");
		//最后一行不打印---|---|---
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				//最后的|不打印
				if (j < col - 1)
				{          
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

这两个是使我们的棋盘最终定型所用的函数,由于我们要在数组里输入数据落子,同时为了保证美观性,所以我们必须保证二维数组里的所有数据都是空格,然后打印棋盘的时候不打印|与—|—|—我们进行了如上所改。最终才打印这种我们想要的棋盘:

有了棋盘接下来我们进行落子:

void player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	printf("玩家请落子:>\n");
	while (1)
	{
		printf("请输入落子坐标:");
		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] = '*';
				
				//清理屏幕,每输出完后都清理历史痕迹
				system("cls");
				break;
			}
			else
			{
				printf("该位置已落子,请重新输入!\n");
			}
		}
		else
		{
			printf("已超出棋盘范围,请重新落子!\n");
		}
	}

}

//电脑下棋
void computer_move(char board[ROW][COL], int row, int col)
{
	printf("电脑落子\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';

			system("cls");
			//清理屏幕
			break;
		}
	}
}

为了保证我们与电脑之间的下棋始终都在一个不变的棋盘上,我们使用了system()函数,每次落子都清理历史屏幕,这就使得我们像视频里那样,屏幕里始终只有一个棋盘。

落完子最后一步便是胜负的判定了:

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

	}
	return 1;
		
}

//胜负可能,列举
char is_win(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][2] != ' ')
		{
			return board[i][2];
		}

	}
	//列获胜的可能
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' ')
		{
			return board[2][i];
		}

	}
	//斜着获胜的可能

	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != ' ')
	{
		return board[2][2];
	}
	if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[0][2] != ' ')
	{
		return board[2][0];
	}
	
	//平局可能
	if (is_full(board,row,col) == 1)
	{
		return 'Q';
	}

	//继续游戏
	return 'C';
}

上面,我们把所有取胜的结果全罗列了出来,那一行一列要么是*要么是#,所以我们直接返回它落的棋子,假如返回#,说明那一行或一列或斜着都是#。同时在这里我们又调用了一个函数,is_full()用来判断假如棋盘落子已满,将是平局。最后假如都不满足,就说明胜负未分,棋盘未满,游戏继续。

我们跟着逻辑走,把所有可能性想全,就可以保证我们写出来的代码又条理清楚,又可以完美运行。 到这里的时候,我们再进行调试,就发现可以很完美的进行游戏了。我们就可以奖励自己一顿大餐!再接再厉!!!

完整代码

测试源文件里的:
#define _CRT_SECURE_NO_WARNINGS 1

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

void game()
{
	char ret = 0;
	//二维数组的创建
	char board[ROW][COL] = {0};

	//初始化棋盘
	init_board(board, ROW, COL);
	//打印棋盘
	display_board(board, ROW, COL);
	//玩游戏环节
	while (1)
	{
		//玩家下棋
		player_move(board, ROW, COL);
		//判断局面
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;

		}
		//打印棋盘

		display_board(board, ROW, COL);

		//电脑下棋
		computer_move(board, ROW, COL);
		//判断局面
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		//打印棋盘

		display_board(board, ROW, COL);

	}
	//我们自己规定,假如函数is_win(board, ROW, COL)返回值为*,表示玩家获胜
	//假如函数is_win(board, ROW, COL)返回值为#,表示电脑获胜
	//假如函数is_win(board, ROW, COL)返回值为C,表示继续游戏
	//假如函数is_win(board, ROW, COL)返回值为Q,表示平局



	if (ret == '*')
	{
		printf("-----------------------------------------------\n");
		printf("------------  !!!  VICTORY  !!!  --------------\n");
		printf("-----------------------------------------------\n");
		printf("----------- !!! 玩家获胜  !!! -----------\n");
		printf("-----------------------------------------------\n");

	}
	else if (ret == '#')
	{
		printf("-----------------------------------------------\n");
		printf("-------------  !!!  DEFEAT  !!!  --------------\n");
		printf("-----------------------------------------------\n");
		printf("----------- !!!  电脑获胜  !!! ----------\n");
		printf("-----------------------------------------------\n");

	}
	else if (ret == 'Q')
	{
		printf("--------------------------------------------\n");
		printf("---------------  !!!DRAW!!!  ---------------\n");
		printf("--------------------------------------------\n");
		printf("----------- !!!  平局  !!! -----------\n");
		printf("--------------------------------------------\n");
	}
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		//菜单
		menu();
		printf("请选择:>");
		scanf("%d", &input);

		//清理屏幕
		system("cls");
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("输入错误,请重新输入“:>\n");
			break;
		}

	} while (input);

	return 0;
}
用来放函数定义的源文件:
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

//棋盘初始化
void init_board(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 display_board(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)//第col-1列不打印|
			{
				printf("|");
			}
		}
		//换行
		printf("\n");
		//最后一行不打印---|---|---
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				//最后的|不打印
				if (j < col - 1)
				{          
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

//玩家下棋
void player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	printf("玩家请落子:>\n");
	while (1)
	{
		printf("请输入落子坐标:");
		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] = '*';
				
				//清理屏幕,每输出完后都清理历史痕迹
				system("cls");
				break;
			}
			else
			{
				printf("该位置已落子,请重新输入!\n");
			}
		}
		else
		{
			printf("已超出棋盘范围,请重新落子!\n");
		}
	}

}

//电脑下棋
void computer_move(char board[ROW][COL], int row, int col)
{
	printf("电脑落子\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';

			system("cls");
			//清理屏幕
			break;
		}
	}
}

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

	}
	return 1;
		
}

//胜负可能,列举
char is_win(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][2] != ' ')
		{
			return board[i][2];
		}

	}
	//列获胜的可能
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' ')
		{
			return board[2][i];
		}

	}
	//斜着获胜的可能

	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != ' ')
	{
		return board[2][2];
	}
	if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[0][2] != ' ')
	{
		return board[2][0];
	}
	
	//平局可能
	if (is_full(board,row,col) == 1)
	{
		return 'Q';
	}

	//继续游戏
	return 'C';
}
头文件
#pragma once
//printf函数所包含头文件
#include<stdio.h>

//rand函数所包含的头文件
#include<stdlib.h>
//时间戳,生成随机数使用
#include<time.h>
//清理屏幕,system()使用
#include<Windows.h>
#define ROW 3
#define COL 3

//棋盘初始化
void init_board(char board[ROW][COL], int row, int col);

//打印棋盘
void display_board(char board[ROW][COL], int row, int col);

//玩家下棋
void player_move(char board[ROW][COL], int row, int col);

//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);

//判断局面
char is_win(char board[ROW][COL], int row, int col);

望诸君加油!!!