三子棋C编写逻辑详解(只是逻辑,不是一篇完整代码)

要写出三子棋,我们首先要想好游戏框架。

基本逻辑:我用模块化编程,文件分为

测试文件:test.c

游戏实现文件:game.h 和 game.c  

测试文件里,我会写出游戏的整个逻辑。而游戏实现文件里,我会写出游戏具体是怎样运行的。

测试文件

void menu()
{
	printf("**********************\n");
	printf("******* 1.play  ******\n");
	printf("******* 0.exit  ******\n");
	printf("**********************\n");
	printf("请选择:");
}
void test()
{
	int input = 0;
	do
	{
		menu();//打印菜单

		scanf("%d", &input);

		switch (input)
		{
		case 1: printf("开始游戏:>\n");
			game();
			break;

		case 0: printf("结束游戏:>\n");
			break;
		}

	}while (input);
}

游戏文件 

然后,我们开始写game()函数

三子棋,无非就是一个3 X 3的表格,说到表格,我们自然而然会想到二维数组。

没错,我们可以定义一个二维数组,然后我们人和电脑在这个二维数组里面下棋。

//用宏定义棋盘大小,可以方便以后改棋盘大小
//但是这里我就只演示三子棋,如有兴趣自行研究
#define ROW 3
#define COL 3

char board[ROW][COL];//定义数组

//把数组传入进行初始化,初始化为全空格
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] = ' ';
		}
	}
}

 数组有了,我们还需要棋盘,这样可以让程序更好看。

   |   |   
---|---|---
   |   |
---|---|---
   |   |

这个棋盘怎么打印

我们不妨把棋盘看成2排字符,用三次,并且把多余的部分去掉

第一部分,如图我们打印3个空格再打印一个竖杠,如此打印3次是不是就有了第一排的雏形,再把最后次打印的竖杠去掉,就完美了。当然我们会在两个空格的中间打印字符,以达到下棋的目的,所以中间并不是空格而是%c。

第二部分,打印3个横线再来个竖杠,和第一部分同样,如此打印3次是不是就有了第二排的雏形,再把最后次打印的竖杠去掉,就完美了。

void Print_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++)
		{
			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 game(void)
{
	char board[ROW][COL];//定义数组
	Init_Board(board, ROW, COL);//初始化数组全为空格

	Print_Board(board, ROW, COL);//打印棋盘

	while (1)//开始下棋
	{
        
	}

}

 游戏不是下一次就完了,所以我们采用循环。

接下来,我们写玩家和电脑怎样下棋

下棋,就是往二维数组中输入一个字符再把它打印到屏幕上就好了。

但是我们还是要考虑一些问题,比如万一玩家不明白代码的底层逻辑:数组是从0开始的,但是我们日常生活中行和列都是从1开始的。

还有玩家输入的位置超出数组的范围了,输入的位置已经有棋子了等,这些都是我们作为游戏设计者要想到的。

void Player_Move(char board[ROW][COL], int row, int col)
{
	while (1)
	{
		printf("玩家下棋->");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		if (x <= row && x > 0 && y <= col && y > 0)//是否在数组范围内
		{
            //将常识输入转换为数组的下标
			x = x - 1;
			y = y - 1;
			if (board[x][y] == ' ')//是否有重复输入
			{
				board[x][y] = '*';
				break;
			}
			else
			{
				printf("输入错误,请重新输入\n");
			}
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	}
}

比起玩家下棋,电脑下棋容易得多,我们只需要生成随机值,再将随机值作为数组的下标输入就行。当然我们还是要考虑输入重复问题。

void Computer_Move(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋\n");
	while (1)
	{

        //生成随机数,并且模上row,col就能得到我们想要的下标。
		int x = rand() % row;
		int y = rand() % col;


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

 玩家电脑下完棋了,我们还需要对输赢进行判断。

在这分为4中情况

'#'为电脑赢
'*'为玩家赢
'P'为平局
'C'为没分出胜负,继续游戏

 接下来是重头戏,也是这个程序最巧妙的地方

我们都知道三子棋,只要有3个棋子相同,就能获胜

但是程序是怎么知道是玩家打印的字符还是电脑打印的呢?

玩家输入,打印 '*' 。电脑输入,打印 '#' 。

进行比较,如果有三个字符相同且不是空格的话,Is_Win函数返回 '*' 或 '#'  来进行判断是玩家打印的字符相同还是电脑打印的字符相同。

如果棋盘满了,那就是平局Is_Win函数返回 'P' 。

如果以上3种情况都不满足则Is_Win函数返回 'C' 。

//static修饰,让Is_Full函数只能在game.c文件中使用。

//Is_Full函数是Is_Win函数的一部分,用于判断是否平局。

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



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


    //都不是返回'C'继续游戏
	return 'C';
}

 game函数全貌

void game(void)
{
	char ret = 0;
	char board[ROW][COL];//定义数组
	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 == 'P')
		printf("平局\n");
}

game.h头文件

#pragma once

#define ROW 3
#define COL 3

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);

看到这,三子棋逻辑你看懂了嘛? 

 希望这篇小博客能帮到你。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值