利用C语言实现三子棋游戏

文章目录

1.游戏界面

无论写任何程序,我们都需要先去了解它的大概框架,这里我们先把它的初始界面写出来。一个游戏的初始界面会有菜单可供选择,这里我写了一个最基础的游戏菜单,只支持开始游戏和退出游戏。为了能够在不退出游戏的情况下一直游玩,所以这里我写了一个do while循环来让游戏一直进行下去。

c 复制代码
#include <stdio.h>
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:
			break;
		}
	}while(input);
	return 0;
}

2.游戏内容

2.1 棋盘类型

写完游戏的界面就轮到了游戏的内容了,让我们来想想三子棋有什么特点,最先想到就是它那3*3的棋盘了,为了实现这个棋盘我们要利用数组来实现。用什么类型的数组呢?这里我会用字符类型的数组,毕竟下棋用数字来作为棋子还是不容易区分的。

c 复制代码
void game()
{
	//创建棋盘
	char chess[4][4] = {0};
}

2.2棋盘的初始化

选择了用字符数组来作为棋盘,初始化我会用' '(空格)来初始化。空格初始化的好处就是不可见,当我们下好棋子后用相应的字符去覆盖掉空格就可以了。

这里我用4*4的数组是为了后续普通用户在用下标下棋时,不用考虑数组下标是0开始的,增加用户的受众。

为什么用多文件编写代码,多文件的编写可以便于后续的修改,多文件可以让代码的可读性更高。

注意头文件game.h放的是函数的声明,game.c放的是函数的定义 test.c是对程序的测试

c 复制代码
//game.h
#include <stdio.h>
//以row为行,col为列

void InitChess(char chess[4][4],int row,int col);

//game.c
#include "game.h"
void InitChess(char chess[4][4],int row,int col)
{
	for(int i = 1;i<4;++i)
	{
		for(int j = 1;j<4;++j)
		{
			chess[i][j] = ' ';
		}
	}
}

//test.c
#include "game.h"
void game()
{
	//创建棋盘
	char chess[4][4] = {0};
	//初始化棋盘
	InitChess(chess,4,4);
}

对函数拓展性的优化,这里的棋盘已经被固定,如果后续我们想要修改棋盘的大小是很麻烦的,所以我们可以定义标识常量。

c 复制代码
//game.h
#include <stdio.h>
//以row为行,col为列
#define Row 4
#define Col 4

void InitChess(char chess[Row][Col],int row,int col);

//game.c
#include "game.h"
void InitChess(char chess[Row][Col],int row,int col)
{
	for(int i = 1;i<row;++i)
	{
		for(int j = 1;j<col;++j)
		{
			chess[i][j] = ' ';
		}
	}
}

//test.c
#include "game.h"
void game()
{
	//创建棋盘
	char chess[Row][Col] = {0};
	//初始化棋盘
	InitChess(chess,Row,Col);
}

2.3 打印棋盘的界面展示

如果我们直接打印这个数组是什么也看不到的,为了让游玩的人可以轻松知道棋盘各个点的坐标,我们要把棋盘打印成这个样子。

c 复制代码
void ChessBoard(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			printf(" %c ", chess[i][j]);
			if (j < col - 1)//否则打印最后一个'|',导致右端封闭
				printf("|");
		}
		printf("\n");
		if (i < row - 1)
		{
			for (int j = 1; j < col; ++j)
			{
				printf("--- ");
			}
			printf("\n");
		}

	}
}

3.游戏操作

3.1 玩家操作

三子棋的游戏操作就是在3*3的方格当中选一个未被下过的方格中落子。

当前游戏并不支持双人对战,所以只能实现人机对战。下面为玩家操作:

c 复制代码
void Gamer(char chess[Row][Col], int row, int col)
{
	int x = 0;//横坐标
	int y = 0;//纵坐标
	while (1)
	{
		printf("选择落子坐标>\n");
		printf("坐标之间用空格区分\n");
		scanf("%d %d", &x, &y);
		//判断坐标是否合法
		if (x<1 || x>Row - 1 || y<1 || y>Col - 1)
		{
			printf("坐标不合法\n");
		}
		//判断所选坐标是否被占据
		else if (chess[x][y] != ' ')
		{
			printf("该坐标被占据\n");
		}
		else
		{
			chess[x][y] = 'O';
			printf("落子成功\n");
			break;
		}
	}
}

3.2 电脑操作

电脑的逻辑和玩家一样,这里我们让电脑随机下棋。

c 复制代码
void Computer(char chess[Row][Col], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % (row - 1) + 1;
		y = rand() % (col - 1) + 1;
		if (chess[x][y] != ' ')
		{
			//
		}
		else
		{
			chess[x][y] = 'X';
			break;
		}
	}
}

因为这了我们用了rand函数,所以我必须在前面写上srand来给rand函数提供随机种子,为此我们还需要用到time为srand提供数字来帮助它输出随机种子.
记得加上相应的头文件

c 复制代码
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu()//菜单
		printf("请选择>");
		scanf"%d",&input);
		switch(input)
		{
			case 1:
			game();
			break;
			case 0:
			printf("退出游戏!\n");
			break;
			default:
			break;
		}
	}while(input);
	return 0;
}

3.3 胜负判定

在三子棋当中,任何以方的棋子连成一条线就会判断为获胜,无论是一行还是一列还是斜方向。因为只有少量的情况。我能把所有获胜的情况全部都枚举出来就可以了。

关于返回值,因为我们要根据棋盘字符的连线来判断谁是赢家。

规定:返回 'O'表示玩家赢,'X'表示电脑赢 'D'表示平局 'C'表示游戏继续

c 复制代码
char Winer(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		if (chess[i][1] == chess[i][2] && chess[i][2] == chess[i][3] && chess[i][1] != ' ')
		{
			return chess[i][1];
		}
	}
	for (int j = 1; j < col; ++j)
	{
		if (chess[1][j] == chess[2][j] && chess[2][j] == chess[3][j] && chess[1][j] != ' ')
		{
			return chess[1][j];
		}
	}
	if (chess[1][1] == chess[2][2] && chess[2][2] == chess[3][3] & chess[1][1] != ' ')
	{
		return chess[1][1];
	}
	if (chess[1][3] == chess[2][2] && chess[2][2] == chess[3][1] && chess[2][2] != ' ')
	{
		return chess[1][3];
	}
	//平局,判断棋盘是不是已经满了
	if (IsFull(chess, row, col))
	{
		return 'D';
	}
	return 'C';
}

判断棋盘是否已经下满

c 复制代码
bool IsFull(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			if (chess[i][j] == ' ')
				return false;
		}
	}
	return true;
}

4.代码整合

关于三子棋的简单游戏逻辑就是这么多了,下面我们要把我们写到的函数整合到一起。

c 复制代码
//game.h
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>//rand和srand的头文件
#include <time.h>//time的头文件
#define Row 4
#define Col 4

void InitChess(char chess[Row][Col], int row, int col);

void ChessBoard(char chess[Row][Col], int row, int col);

void Gamer(char chess[Row][Col], int row, int col);

void Computer(char chess[Row][Col], int row, int col);

char Winer(char chess[Row][Col], int row, int col);

bool IsFull(char chess[Row][Col], int row, int col);

//game.c

#include "game.h"

void InitChess(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			chess[i][j] = ' ';
		}
	}
}

void ChessBoard(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			printf(" %c ", chess[i][j]);
			if (j < col - 1)//否则打印最后一个'|',导致右端封闭
				printf("|");
		}
		printf("\n");
		if (i < row - 1)
		{
			for (int j = 1; j < col; ++j)
			{
				printf("--- ");
			}
			printf("\n");
		}

	}
}

void Gamer(char chess[Row][Col], int row, int col)
{
	int x = 0;//横坐标
	int y = 0;//纵坐标
	while (1)
	{
		printf("选择落子坐标>\n");
		printf("坐标之间用空格区分\n");
		scanf("%d %d", &x, &y);
		//判断坐标是否合法
		if (x<1 || x>Row - 1 || y<1 || y>Col - 1)
		{
			printf("坐标不合法\n");
		}
		//判断所选坐标是否被占据
		else if (chess[x][y] != ' ')
		{
			printf("该坐标被占据\n");
		}
		else
		{
			chess[x][y] = 'O';
			printf("落子成功\n");
			break;
		}
	}
}

void Computer(char chess[Row][Col], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % (row - 1) + 1;
		y = rand() % (col - 1) + 1;
		if (chess[x][y] != ' ')
		{
			//
		}
		else
		{
			chess[x][y] = 'X';
			break;
		}
	}
}

char Winer(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		if (chess[i][1] == chess[i][2] && chess[i][2] == chess[i][3] && chess[i][1] != ' ')
		{
			return chess[i][1];
		}
	}
	for (int j = 1; j < col; ++j)
	{
		if (chess[1][j] == chess[2][j] && chess[2][j] == chess[3][j] && chess[1][j] != ' ')
		{
			return chess[1][j];
		}
	}
	if (chess[1][1] == chess[2][2] && chess[2][2] == chess[3][3] & chess[1][1] != ' ')
	{
		return chess[1][1];
	}
	if (chess[1][3] == chess[2][2] && chess[2][2] == chess[3][1] && chess[2][2] != ' ')
	{
		return chess[1][3];
	}
	//平局,判断棋盘是不是已经满了
	if (IsFull(chess, row, col))
	{
		return 'D';
	}
	return 'C';
}

bool IsFull(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			if (chess[i][j] == ' ')
				return false;
		}
	}
	return true;
}

//test.c
#include "game.h"

void game()
{
	//创建棋盘
	char chess[Row][Col] = { 0 };
	//初始化棋盘
	InitChess(chess, Row, Col);
	char w = 0;
	while (1)
	{
		//打印棋盘
		ChessBoard(chess, Row, Col);
		//玩家操作
		Gamer(chess, Row, Col);
		//输赢判断
		w = Winer(chess, Row, Col);
		if (w != 'C')
			break;
		//电脑操作
		Computer(chess, Row, Col);
		//输赢判断
		char w = Winer(chess, Row, Col);
		if (w != 'C')
			break;
	}
	ChessBoard(chess, Row, Col);
	if (w == 'D')
		printf("平局\n");
	else if (w == 'O')
		printf("玩家获胜\n");
	else
		printf("电脑获胜\n");
}
void menu()
{
	printf("*************************\n");
	printf("******* 1.play    *******\n");
	printf("******* 0.exit    *******\n");
	printf("*************************\n");

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

相关推荐
浮生如梦_1 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown4 小时前
【数据结构】选择排序
数据结构·算法·排序算法
aloha_7894 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
hikktn5 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
PandaQue5 小时前
《怪物猎人:荒野》游戏可以键鼠直连吗
游戏
观音山保我别报错5 小时前
C语言扫雷小游戏
c语言·开发语言·算法