三子棋(N子棋)小游戏超详解

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

三子棋写成的效果如下
在这里插入图片描述

写成N子棋 效果如下(其中拿五子棋做示范)
在这里插入图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、三子棋的游戏规则?

游戏规则要求:电脑(随机)和玩家一次下一子,双方轮流交替下子,直到电脑和玩家任意一方获胜,或者棋盘满了,结束游戏。

获胜判定:只要电脑或者玩家任意一方的棋子有三子连在一起,可以为横连、纵连、斜连,则该方获胜,游戏结束。若棋盘满了,则判定为平局。

二、三子棋的游戏设计的大概思路?

实现程序的思路:首先我们需要定义游戏菜单和游戏规则。

游戏菜单:选择是否开始玩儿游戏,1:玩儿,0:退出游戏;

游戏规则:电脑先走,玩家后走,一方棋子有三子连在一起即为赢,否则棋盘满还未有一方赢判定为平局。

接下来就是开始玩儿游戏了(游戏过程):打印棋盘 → 电脑走一步 → 玩家走一步 → 判定输赢 or 平局 。(为了最后的显示效果,任意一方走一步就打印一次棋盘)。

棋盘初始化 → 打印棋盘 → 设定棋盘的行列数 → 打印盘的样式;

电脑走 → 设定电脑走的随机坐标(棋盘上有空位才能走);

玩家走 → 输入家走的坐标 → 有空位就打印出棋子(还需要考虑坐标被占用和输入坐标不合法两种情况);

判断输赢 → 棋盘上的横连、纵连、斜连有三子一样的即为该方赢 → 棋盘满了即为平局。

三、设计详细思路加代码

为了确保程序的独立性
我们创造两个源文件game.c和text.c,一个头文件game.h实现程序的模块化进行
其中game.c用来实现整个游戏的具体操作
text.c用来最终调用game.c来实现运行
这就需要创造一个头文件game.h来实现上述的调用

1.首先定义一个菜单menu函数

代码如下(示例):

//游戏菜单:选择是否开始玩儿游戏,1:玩儿,0:退出游戏;
void menu()
{
	printf("*************************\n");
	printf("******** 1.play  ********\n");
	printf("******** 0.exit  ********\n");
	printf("*************************\n");
}

2.在test函数中调用menu函数

使用函数调用的方式实现

void test()
{
	//srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)//采用switch函数实现选择,选择1就进行game,选择0就退出,其他就重新选择
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
}

3.在main函数中在调用test函数

int main()
{
	test();
	return 0;
}

4.以上均在text.c中进行,然后我们需要在text.c文件中调用game函数,然后在game.c的源文件实现其功能,实现game函数的具体思路和代码如下

1.创造一个二维数组,用来打印棋盘

void game()
{
  char board[3][3];
}

为避免创造棋盘的维数受到限制,我们在头文件game.h中定义两个define定义的常变量ROW(行)和COL(列)(column)来表示打印棋盘的行和列
这样我们仅需要该其后面的数字就可以玩我们想玩的维数棋盘了

#define ROW 3
#define COL 3

然后将数组后的行列改为ROW,COL就可以在只改变头文件中ROW,COL后定义的数字控制需要打印的棋盘维数了

void game()
{
   char board[ROW][COL];
}

2.实现棋盘的初始化

将棋盘全部初始化为空格
在text.c中game函数中调用init_board(board, ROW, COL)函数,并传入行和列
并将其放在头文件game.h中定义

void game()
{
   char board[ROW][COL];
   //初始化一下棋盘为全空格
	init_board(board, ROW, COL);
}

在game.h中声明

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

并在game.c中文件中实现

void init_board(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] = ' ';
		}
	}
}

3.将棋盘初始化后就是打印棋盘了

因此在text.c中game函数中调用print_board(board, ROW, COL);函数并传入行和列
同样的头文件game.h中进行声明
在到game.c文件中进行实现

void game()
{
   char board[ROW][COL];
   //初始化一下棋盘为全空格
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);
}

在game.h中定义

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

并在game.c中文件中实现

//打印棋盘(只能打印三子棋)
void print_board(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
		if(i<row-1)
      printf("---|---|---\n");
	}
}

这中打印方式是固定打印三子棋3x3的棋盘了,相当于把代码写死了,接下来的另一种代码只要在以上代码的基础上进行修改即可

N子棋棋盘打印

//打印棋盘(优化:可以打印任意维数棋盘)
void print_board(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		//printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
		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)
		{
			//printf("---|---|---\n");
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}

4.接下来就是玩家和电脑分别进行下棋了

同样也是以上思路
在text.c文件中game函数中先调用且传入行和列
并在头文件game.h中声明
在game.c中实现
代码如下

void game()
{
	//存放玩家或者电脑的落子情况
	char board[ROW][COL];
	char ret = 0;
	//初始化一下棋盘为全空格
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);

	while (1)
	{
        //玩家下棋
	    player_move(board, ROW, COL);
		print_board(board, ROW, COL);
		//电脑下棋
	    computer_move(board, ROW, COL);
		print_board(board, ROW, COL);
    }
}

在game.h中声明

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

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

并在game.c文件中实现

//玩家下棋
void player_move(char board[ROW][COL], int row, int col)
{
	printf("玩家下棋");
	while (1)
	{
		printf("请输入要下的坐标");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')//由于玩家不会考虑到数组下标是从0开始,故要按玩家输入的坐标减一放入
			{
				board[x - 1][y - 1] = '*';
				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] = '#';
			break;
		}
	}
}

而电脑是用rand函数实现随机数需要test.c文件中的主函数main中使用srand((unsigned int)time(NULL));来实现随机数自由

int main()
{
	srand((unsigned int)time(NULL));
	test();
	return 0;
}

当然在使用库函数srand,rand,time时是也要在头文件game.h进行声明

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

5.最后是判断输赢了

我们规定:
判断输赢的代码要告诉我:电脑赢了?玩家赢了?玩家赢?游戏继续?
//电脑赢:#
//玩家赢:*
//平局:Q
//游戏继续:C

思路同样如上
我们先在text.c文件中game函数调用is_win(board, ROW, COL);来判断胜负,并传入行和列,其中is-win函数返回值用ret接收
同时在头文件game.h中声明
最后在game.c文件中实现
代码如下

void game()
{
	//存放玩家或者电脑的落子情况
	char board[ROW][COL];
	char ret = 0;
	//初始化一下棋盘为全空格
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);

	while (1)
	{

	    player_move(board, ROW, COL);
		print_board(board, ROW, COL);
		//判断输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	    computer_move(board, ROW, COL);
		print_board(board, ROW, COL);
		//判断输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '#')
		printf("电脑赢了\n");
	else if (ret == '*')
		printf("玩家赢了\n");
	else if (ret == 'Q')
		printf("平局\n");
}

在头文件game.h中声明

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

在到game.c文件中实现

//只能判断三子棋输赢
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][0] != ' ')
		{
			return board[i][0];
		}
	}
		for (i = 0;  i< col; i++)
		{
			if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
			{
				return board[0][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];
		}

		if (is_full(board, row, col) == 1)//判断平局,代码在下
		{
			return 'Q';
		}
	return 'C';

同样的和上面打印棋盘时相似,该种判断方式只能判断三子棋的输赢,相当于把代码写死了
对其进行优化,使其能不受限制,在任意N子棋都能判断输赢

N子棋棋盘判断输赢

//判断输赢(优化版:可判断任意维数棋局的输赢)
char is_win(char board[ROW][COL], int row, int col)
{
	//行判断
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int count = 0;
		for (j = 0; j < col - 1; j++)
		{
			if (board[i][j] == board[i][j + 1] && board[i][j] != ' ')
			{
				count++;
			}
			if (count == col - 1)
				return board[i][j];
		}

	}
	
	//列判断
	for (i = 0; i < col; i++)
	{
		int j = 0;
		int count = 0;
		for (j = 0; j < row - 1; j++)
		{
			if (board[j][i] == board[j + 1][i] && board[j][i] != ' ')
			{
				count++;
			}
			if (count == row - 1)
				return board[j][i];
		}
	}
	
	// '/'判断
	for (i = 0; i < row - 1; i++)
	{
		if (board[i][row - 1 - i] == board[i + 1][row - 2 - i] && board[i][row - 1 - i] != ' ')
		{
			if (row - 2 - i == 0)
				return board[i][row - 1 - i];
		}

	}
	
	// '\' 判断
	for (i = 0; i < row - 1; i++)
	{
		if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' ')
		{
			if (i == row - 2)
				return board[i][i];
		}
	}
	if (is_full(board, row, col) == 1)
	{
		return 'Q';
	}
	return 'C';
}

当棋盘下满了,出现平局,此时就需要在is_win函数中调用is_ful函数来判断
假如全部满了返回1,没满返回0

int is_full(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;
}

至此三子棋(N子棋)基本完成了
所以总的代码如下
text.c

#include "game.h"


//打印菜单
void menu()
{
	printf("*************************\n");
	printf("******** 1.play  ********\n");
	printf("******** 0.exit  ********\n");
	printf("*************************\n");
}


void game()
{
	//存放玩家或者电脑的落子情况
	char board[ROW][COL];
	char ret = 0;
	//初始化一下棋盘为全空格
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);

	while (1)
	{

	    player_move(board, ROW, COL);
		print_board(board, ROW, COL);
		//判断输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	    computer_move(board, ROW, COL);
		print_board(board, ROW, COL);
		//判断输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	
	if (ret == '#')
		printf("电脑赢了\n");
	else if (ret == '*')
		printf("玩家赢了\n");
	else if (ret == 'Q')
		printf("平局\n");
}

void test()
{
	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);
}

int main()
{
	srand((unsigned int)time(NULL));
	test();
	return 0;
}

game.h

#define ROW 3
#define COL 3

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

//头文件中声明函数

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

//打印棋盘
void print_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);

game.c

#include "game.h"

//初始化棋盘
void init_board(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] = ' ';
		}
	}
}

//打印棋盘(只能打印三子棋)
void print_board(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
		if(i<row-1)
      printf("---|---|---\n");
	}
}

//代码优化
//打印棋盘(优化:可以打印任意维数棋盘)
//void print_board(char board[ROW][COL], int row, int col)
//{
//	int i = 0;
//	for (i = 0; i < row; i++)
//	{
//		//printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//		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)
//		{
//			//printf("---|---|---\n");
//			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)
{
	printf("玩家下棋");
	while (1)
	{
		printf("请输入要下的坐标");
		int x = 0;
		int y = 0;
		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 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] = '#'; 
			break;
		}
	}
}


//判断是否平局
int is_full(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;
}

//只能判断三子棋输赢
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][0] != ' ')
		{
			return board[i][0];
		}
	}
		for (i = 0;  i< col; i++)
		{
			if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
			{
				return board[0][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];
		}

		if (is_full(board, row, col) == 1)
		{
			return 'Q';
		}
	return 'C';
}

//代码优化
//判断输赢(优化版:可判断任意维数棋局的输赢)
//char is_win(char board[ROW][COL], int row, int col)
//{
//	//行判断
//	int i = 0;
//	for (i = 0; i < row; i++)
//	{
//		int j = 0;
//		int count = 0;
//		for (j = 0; j < col - 1; j++)
//		{
//			if (board[i][j] == board[i][j + 1] && board[i][j] != ' ')
//			{
//				count++;
//			}
//			if (count == col - 1)
//				return board[i][j];
//		}
//
//	}
//	//列判断
//	for (i = 0; i < col; i++)
//	{
//		int j = 0;
//		int count = 0;
//		for (j = 0; j < row - 1; j++)
//		{
//			if (board[j][i] == board[j + 1][i] && board[j][i] != ' ')
//			{
//				count++;
//			}
//			if (count == row - 1)
//				return board[j][i];
//		}
//	}
//	// '/'判断
//	for (i = 0; i < row - 1; i++)
//	{
//		if (board[i][row - 1 - i] == board[i + 1][row - 2 - i] && board[i][row - 1 - i] != ' ')
//		{
//			if (row - 2 - i == 0)
//				return board[i][row - 1 - i];
//		}
//
//	}
//	// '\' 判断
//	for (i = 0; i < row - 1; i++)
//	{
//		if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' ')
//		{
//			if (i == row - 2)
//				return board[i][i];
//		}
//	}
//	if (is_full(board, row, col) == 1)
//	{
//		return 'Q';
//	}
//	return 'C';
//}

四.总结

我的第一篇博客大功告成,花费的时间和精力总会获得回报
还是小有成就感呢!
继续努力!加油,奥里给!
有不对的请及时指正我!谢谢读者

此外

对于三子棋还可以继续完善
比如:让电脑智能下棋,学会堵棋
或者是电脑有套路化的下棋等等

时间精力充裕的话可以试着去想想此类代码
我们不急慢慢来

  • 47
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值