C语言趣味小游戏——三子棋

全篇无任何废话,本文的解释大多数都在代码段中,所以一定要看代码,边看边学边理解。

这只是初学者入门的一个小游戏,不难懂,没有什么复杂的内容

可以先学习一下比三子棋还简单的猜数字小游戏

C语言趣味小游戏——猜数字(匠心制作)

游戏的条件

1.根据坐标和电脑下棋,玩家一步棋,电脑一步棋,且不能悔棋

2.玩完一盘可以继续

可以学到的内容

1.打印一个简单的菜单

2.一些细节的用户体验

3.自定义函数  ,  时间戳的运用  ,  #define定义

4.程序语言的一些入门逻辑

5.C语言的知识

————————————————————————————————————————

首先来一个简简单单的代码三部曲(写在test.c的文件下,后期有妙用)

//    测试三子棋游戏的逻辑

#include

int main()
{

	return 0;
}

写一个返回值为void的test函数,且调用它

void test()
{

}

int main()
{
	test();

	return 0;
}

因为是玩游戏,所以写一个do  while,并且打印菜单,和猜数字异曲同工

void menu()
{
	printf("*********************\n");
	printf("****** 1.play  ******\n");
	printf("****** 0.over  ******\n");
	printf("*********************\n");
}

void test()
{
	do
	{
		menu();    //    菜单

	} while ();

}

看到菜单之后就做出选择

void test()
{
	int input = 0;	//	初始化
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);	//	输入

	} while ();

}

 定义一个整型并初始化,方便后期输入

void test()
{
	int input = 0;	//	初始化
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);    //    输入

	} while ();	
}

加入switch语句

不懂得switch,case,default语句和do while循环可以看下这个,1分钟就懂了

https://blog.csdn.net/W20223161730/article/details/126200624?spm=1001.2014.3001.5502

void test()
{
	int input = 0;	//	初始化
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);	//	输入
		switch(input)		//	这里使用input的原因是根据输入的值进入对应的case语句
		{
		case 1:
			//		假设这里有三子棋游戏
			printf("玩游戏!\n");
			break;
		case 0:
			printf("选择退出,游戏结束!\n");
			break;
		default :
			printf("选择错误,请重新输入!\n");
			break;
		}
	} while (input);	//		这里使用input的原因是根据input判断是否继续,如果输入的是1 为真(继续),否则 0为假(结束)

}

开始实现游戏的主体        (需要先去了解一下什么是二维数组)

1:游戏开始肯定会呈现一个九宫格的棋盘,三行三列,且中间什么都没有,输入坐标下棋后会被覆盖

2:被覆盖之后会被打印出来,也就是说,棋盘以及玩家和电脑的棋子会被存储起来

3:如果想要实现棋盘中间什么的没有,那么中间肯定是空格

正片开始 :        初始化一个名为board的二维数组,得是三行三列

void game()
{
	//	存放下棋的数据
	char board[3][3] = { 0 };
}

再初始化棋盘为全空格,后面还会有更多这样的操作,为了方便所以就直接封装成函数,分模块来写

void game()
{
	//	存放下棋的数据
	char board[3][3] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, 3, 3);
}

所以再添加一个game.c 和game.h 的两个文件

在test.c文件里面有了这个函数之后,声明就放在game.h的头文件里面

在函数声明的时候需要告诉函数它的返回类型,参数等

//        名字为game.h 的头文件

//	初始化棋盘		棋盘			      行   	   列

void Initboard(char board[3][3], int row, int col);

然后再用define在.h中定义一下行和列,免得后期更改比较麻烦

#define ROW 3
#define COL 3

//	初始化棋盘		棋盘			      行   	   列

void Initboard(char board[3][3], int row, int col);

把文件里的行和列都替换成define定义的ROW和COL

记得在文件中包含game.h ↓

#include"game.h"

顺便把game.h文件中写上三部曲的第一步

#include

这样做的目的是其他文件包含game.h,而game.h文件又包含了行和列还有三部曲的第一部,会节省很多时间

//    game.h 文件
#pragma once

#include

#define ROW 3
#define COL 3

//	初始化棋盘		棋盘			      行   	   列

void Initboard(char board[ROW][COL], int row, int col);



//       game.c 文件

#include"game.h"

void Initboard(char board[ROW][COL], int row, int col)
{

}



//       test.c 文件

#include"game.h"

然后声明完了放到game.c 的文件中实现

void Initboard(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++)
		{
			board[i][j] = ' ';
		}
		printf("\n");
	}
}

在test.c文件中来一个打印棋盘的函数

void game()
{
	//	存放下棋的数据
	char board[ROW][COL] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, ROW, COL);

	//	打印棋盘

	Displayboard(board, ROW, COL);
}

还是头文件

void Displayboard(char board[ROW][COL], int row, int col);

game.c文件

void Displayboard(char board[ROW][COL], int row, int col)
{
	
}

棋盘打印还是需要精心设计的,这里就不过多赘述,直接上代码

void Displayboard(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++)
		{
			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");

		}
	}
}

效果图

C语言趣味小游戏——三子棋_第1张图片

后面就开始重中之重了,玩家和电脑是如何下棋的 

还是继续写一个函数 用来实现玩家下棋

//    test.c

	Player_move(board, ROW, COL);

//    game.c

void Player_move(char board[ROW][COL], int row, int col)
{

}

//    game.h

void Player_move(char board[ROW][COL], int row, int col);

需要提前考虑到两点

1:玩家的非法输入

2:玩家输入并不知道数组的下标是从0开始,所以需要加1

void Player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋!\n");
	printf("请输入坐标!\n");
	scanf("%d %d", &x, &y);

	if (x >= 1 && x <= row && y >= 1 && y <= col)
	{
    
	}
	else
	{
		printf("坐标输入错误,请重新输入!\n");
	}

}

 玩家不可能就输入错误一次,所以加上一个循环才是合理的

void Player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋!\n");

	while (1)
	{
		printf("请输入坐标!\n");
		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{

		}
		else
		{
			printf("坐标输入错误,请重新输入!\n");
		}
	}

}

下一步

if (x >= 1 && x <= row && y >= 1 && y <= col)
{
	if (board[x - 1][y - 1] == ' ')		//	玩家输入的要减1,因为数组的下标是从0开始的
										
		//		如果输入的是一个空格,那么就说明这个位置没有被占用
	{
		board[x - 1][y - 1] == '*';		//	那么就把空格替换成 * 来当作玩家下的棋
            
            break;
        
        //    一定要记得break,不然一直死循环    
	}
	else
	{
		printf("该坐标被占用,请重新输入!\n");
	}
}

再重新打印一下棋盘

void game()
{
	//	存放下棋的数据
	char board[ROW][COL] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, ROW, COL);

	//	打印棋盘

	Displayboard(board, ROW, COL);

	//	玩家下棋

	Player_move(board, ROW, COL);

    //    重新打印

	Displayboard(board, ROW, COL);

}

效果图

C语言趣味小游戏——三子棋_第2张图片

然后开始写一个简单的电脑下棋函数,以后感兴趣可以自行加上堵截,优先胜利的代码,这次就先不过多介绍,因为是入门先理解

//    test.c

	Computer_move(board, ROW, COL);

//    game.c

void Computer_move(char board[ROW][COL], int row, int col)
{

}

//    game.h

void Computer_move(char board[ROW][COL], int row, int col);

那么问题来了,怎么控制让电脑在规定的范围内,且不重复的下棋

需要简单的了解rand,srand,time函数

C语言趣味小游戏——三子棋_第3张图片

C语言趣味小游戏——三子棋_第4张图片

C语言趣味小游戏——三子棋_第5张图片

这个函数调用一次,每次就归零一次(重新开始),所以不需要频繁的调用,只需要调用一次就可以了, 所以直接放到主函数的test函数里面

	srand((unsigned int)time(NULL));

在game.h的头文件包含一下

#include		//	srand
#include		//	time

电脑下棋的实现

void Computer_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋!\n");
	while (1)
	{
		x = rand() % row;	//	值为0到2	
		y = rand() % col;	//	值为0到2
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}

}

玩家和电脑下完棋都打印一下 ,下棋不可能只下一步,所以放到循环里面

void game()		//	因为是传参,所以要带上ROW和COL
{
	//	存放下棋的数据
	char board[ROW][COL] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, ROW, COL);

	//	打印棋盘

	Displayboard(board, ROW, COL);

	while (1)
	{
		//	玩家下棋

		Player_move(board, ROW, COL);

		//	下完棋打印一下
		Displayboard(board, ROW, COL);


		//	电脑下棋
		Computer_move(board, ROW, COL);

		//	下完棋打印一下
		Displayboard(board, ROW, COL);
	}

}

效果

C语言趣味小游戏——三子棋_第6张图片C语言趣味小游戏——三子棋_第7张图片

现在还需要实现怎么判断输赢的函数

什么情况下属于游戏结束

1:玩家赢                2:电脑赢                3:平局                或者        :继续

所以封装成一个函数来用是最方便的                那么直接硬写肯定是不太行的

所以当目的达到了,返回一个特定的符号,如果是返回的情况,一定需要一个用来接收的内容

//		玩家赢---'*'
// 
//		电脑赢---'#'
// 
//		平局---'Q'
// 
//		继续---'C'
//

而且每下完一步棋,都需要判断一下,所以这个判断输赢的函数要放在玩家和电脑下完棋之后

void game()		
{
	//	接收is_win的返回类型

	char ret = 0;

	//	存放下棋的数据
	char board[ROW][COL] = { 0 };

	//	初始化棋盘为全空格

	Initboard(board, ROW, COL);

	//	打印棋盘

	Displayboard(board, ROW, COL);

	while (1)
	{
		//	玩家下棋

		Player_move(board, ROW, COL);

		//	下完棋打印一下
		Displayboard(board, ROW, COL);

		//	再判断一下输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')			//	等于'C'继续,不等于'C'就是有胜利的一方或者平局
		{
			break;
		}

		//	电脑下棋
		Computer_move(board, ROW, COL);

		//	下完棋打印一下
		Displayboard(board, ROW, COL);

		//	再判断一下输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')			//	等于'C'继续,不等于'C'就是有胜利的一方或者平局
		{
			break;
		}
	}
	//		break结束跳到这里

}

再来判断输赢或者平局

	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}

最后一步,实现判断输赢函内容的细节

三子棋输赢的判断就是三个棋子在行,列,对角线是否三子相连   

1:       用来判断行是否相等     

	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][2];
		}
	}

灵魂画手上线

C语言趣味小游戏——三子棋_第8张图片 

如果玩家赢,返回的就是玩家的棋子 *       ,如果电脑赢,返回的就是电脑的棋子 #

2:        用来判断列是否相等

	int i = 0;
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[2][i];
		}
	}

C语言趣味小游戏——三子棋_第9张图片

一定要加上不等于  ' '  因为要把空格排除在外

3:       用来判断两条对角线是否相等

 C语言趣味小游戏——三子棋_第10张图片

	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];
	}

 4:        判断平局的情况

在game.c的文件中实现一个判断平局的函数,不需要在.h文件中实现,因为这个函数并不是全局的,仅仅用于判断平局

加上 static 只能在本文件下使用


static 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;		//		棋盘被下满了
}

 放到        is_win函数内部来使用

	//		用来判断平局
	if (is_full(board, row, col) == 1)
	{
		return 'Q';
	}

	//		游戏继续
	return 'C';

最后:    整体代码不会放出来的,希望大家能一步步的看,一步步的实现,多的不说了,加油!

你可能感兴趣的:(C语言,c++,c++,c语言,算法)