三子棋解析

#include<stdio.h>
int main()
{
	int input = 0;
	do {
		menu();//打印菜单
		srand((unsigned int)time(NULL));
		scanf("%d", &input);
		switch (input)
		{
			case 1:
				game();
				break;
			case 0:
				printf("退出游戏\n");
				break;
			default:
				printf("输入错误,请重新输入!\n");
		}
	} while (input);
	return 0;
}

首先我们需要把游戏的逻辑理清楚,首先我们需要打印菜单,让我们选择是否进入游戏。如果我们中间想退出,或者继续游戏,我们就需要一个循环语句。而do  while 语句是最适合的,而我们把选择是否进入游戏的输入变量变成while的循环条件。所以当我们选择退出游戏,输入0时,循环也就结束了。

这就是一个简易的菜单。

void menu()
{
	printf("******  1.play  *******\n");
	printf("******  0.exit  *******\n");
	printf("***********************\n");
	printf("请选择>");
}

之前都是做游戏的简单准备工作,现在我们才是真正进入游戏的部分。

#define ROW 3
#define COL 3
#include<time.h>
#include<stdlib.h>
#include<stdio.h>
//初始化棋盘
void Initboard(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 Display_board(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL], int row, int col);
//玩家赢  ‘*’
//电脑赢   ‘#’
//平局     ‘P'
//继续      ’t'

我们从头文件开始一步一步分析。

首先我们把ROW COL同时定义为3,目的时为了,当改变棋盘打印时能够更加简单地改成我们想要的棋盘。

下三子棋首先就是要初始化棋盘


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

我们首先知道三子棋棋盘是个二维数组构成的棋盘。

初始化棋盘我们每个期盘都是空的,所以我们选择用一个循环的嵌套将棋盘初始化为一个只有空格的棋盘。

void Initboard(char board[ROW][COL], int row, int col) 
{
	for (row = 0; row <= ROW - 1; row++)
	{
		for (col = 0; col <= COL - 1; col++)
		{
			board[row][col] = ' ';
		}
	}
}

注意这里的row col都要初始化为零,原因就是我们的二维数组不管是行还是列都是从零开始。


//打印棋盘
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)
			{
				printf("|");
			}
		}
		
		printf("\n");

这就是答应一行:(三个空格)| (三个空格)|(三个空格),并且每一行的的二维数组位置都照准棋盘的排列方式。

	if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
		}
		printf("\n");
	}
}

这就是打印一行:(___)         |          (___)     |       (___)

这里我们仅仅需要两行就足够了。所以我们一开始用if语句来控制是否进入该循环。

所以完整的期盼的打印应该是:

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

我们首先先想清楚玩家下棋的逻辑。

当玩家输入正确就将该数组输入 “*”

当玩家输入的地址被占用,就得重新输入

但玩家输入的地址不存在就得重新输入。

所以,我们就清楚该部分应该是循环而且,只有输入正确才能跳出循环。

void player_move(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("玩家下棋>\n");
	
	while (1)
	{
		scanf("%d,%d", &i, &j);
		if (i <= row && j <= row && i >= 1 && j >= 1)
		{
			if (board[i - 1][j - 1] !=' ')
				printf("坐标被占用,请重新输入。\n");
			else
			{
				board[i - 1][j - 1] = '*';
				break;
			}
		}
		else
			printf("坐标非法,请重新输入!\n");
	
	}
}

注意这部分:board[i-1][j-1]

我们知道二维数组是从0开始,但是我们从直观的看数组就是从1开始,所以,我们需要开始时就设置成i-1,j-1,


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

电脑下棋首先我们需要设置两个随机值,这个随机值就需要时间戳来让随机值不断变换,同时还需要保证这个随机值在零到二之间变换,因为我们的二维数组是从零开始到二的。

在下棋之前还需要判断该数组是否被占用,而且我们电脑下的字符还需要和玩家下的不同。我们用警号“#”来代表。在找到空数组之前需要不断在循环中保证电脑能通过随机值找到一个空数组。直到找到空数组才能跳出循环。具体的代码实现如下:

void computer_board(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋>\n");
	int i = 0;
	int j = 0;
	while (1)
	{
		i = rand() % row;
		j = rand() % col;
		if (board[i][j] == ' ')
		{
			board[i][j] = '#';
			break;
		}
	}
}

在我们电脑下棋的函数设置完成后,我们还要考虑如何判断输赢。

char is_win(char board[ROW][COL], int row, int col);
//玩家赢  ‘*’
//电脑赢   ‘#’
//平局     ‘P'
//继续      ’t'

三子棋的的规则就是,有三竖行,三横行,或者两个对角线被一方占据我们就可以判断,输赢,如果在棋盘中没有空的位置也没有一人赢就为平局。

同时我们也知道,只要有一方三行,三竖行,或者对角线被占据,将其中的一个字符传出,并判断是什么字符就可以知道是哪方赢,如果没有一方输赢,或者平局,我们就传出一个值让程序继续。

int is_full(char board[ROW][COL], int row, int col)//判断是否下满棋盘
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; i++)
			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 - 1; i++)//判断三横行
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][1];
		}
	}
	for (int j = 0; j <= col - 1; j++)//判断三竖行
	{
		if (board[0][j] == board[1][j] && board[0][j] == board[2][j] && board[0][j] != ' ')
		{
			return board[0][j]; 
		}
	}
	if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[0][0] != ' ')
	{
		return board[0][0];//判断两个对角线
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
	{
		return board[0][2]; 
	}
	if (is_full(board, ROW, COL) == 0)
	{
		return 't';
	}
	else
	{
		return 'P';
	}
}

在完成了各个部分的设置,我们就需要考虑游戏进行的逻辑。

每次我们玩家下棋或者电脑下棋我们就进行一次判断,根据判断函数的传值,判断是否继续,而且只有判断出输赢平局我们才能退出,所以我们知道这是一个循环。

并且我们每次下棋之后都需要打印出棋盘。


void game()
{
	char board[ROW][COL] = { 0 };
	Initboard(board, ROW, COL);
 	Display_board(board, ROW, COL);
	char ret = 0;

	while (1)
	{
		player_move(board, ROW, COL);
		Display_board(board, ROW, COL);
		 ret = is_win(board, ROW, COL);
		if (ret != 't')
		{
			break;
		}
		computer_board(board, ROW, COL);
		Display_board(board, ROW, COL);
		char ret = is_win(board, ROW, COL);
		if (ret != 't')
		{
			break;
		}
	}
	ret = is_win(board, ROW, COL);
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}

这就是三子棋的实现逻辑了,加油!各位程序猿。

Guess you like

Origin blog.csdn.net/weixin_61652218/article/details/121356300