三子棋-支持N子棋-详解(以及堵截玩家的方法设计)

我可能写的有些啰嗦,见谅,但我会很详细的讲解每一个步骤。

游戏框架的构造(游戏结构的设计)

1,游戏需要菜单
2,需要选项(进入游戏或退出)
3,三子棋需要一个3*3的棋盘
4,需要将棋盘表现(打印出来)
5,玩家要开始下棋(输入坐标)
6,每次落子后都要判断输赢或平局
7,打印目前棋盘的状况
8,电脑开始落子
9,每次落子后都要判断输赢或平局
10,打印目前棋盘的状况
11.判断游戏目前的局面(输或赢,继续落子或者平局)

代码布局设计

由于,代码量过大,并且各个函数的设计及作用。并且考虑N子棋的可能。我们需要分模块,分文件来写。

对游戏布局,初始选项的思考

游戏菜单-进入游戏或者退出—分支语句(switch)
还要打印游戏菜单,使用函数。
为了多次play游戏,也包括多次选项输入,考虑do{}while();循环,可以至少进入一次循环。

void option(int input)
{
    
    
	switch (input)//分支语句
	{
    
    
	case 1:
		game();//进入游戏
		break;
	case 0:
		printf("Logon out the game\n");
		break;
	default:
		printf("Input error,please input again\n");
		break;
	}
}
void menu(void)
{
    
    
	printf("Welcome to game\n");
	printf("\n");
	printf("****************\n");
	printf("*----1.play----*\n");
	printf("*----0.exit----*\n");
	printf("****************\n");
}
int main(void)
{
    
    
	int input;
	//srand((unsigned int)time(NULL));时间戳,为电脑落子设定随机数
	do
	{
    
    
		menu();//打印游戏菜单
		printf("please input option(1/0):>");
		scanf("%d", &input);
		option(input);//选项判断
	} while (input);
	return 0;
}

我们要求输入数字1或0,如果输入其他值,就会default结束,并进入while判断,为,int型,再次循环。

将上述游戏设计实现

1,三子棋需要一个3*3的棋盘
2,需要将棋盘表现(打印出来)
3.玩家要开始下棋(输入坐标)
4.每次落子后都要判断输赢或平局
5,打印目前棋盘的状况
6,电脑开始落子
7,每次落子后都要判断输赢或平局
8,打印目前棋盘的状况

void game(void)
{
    
    
	char ret;
	char board[ROW][COL];//创建二维数组
	setboard(board, ROW, COL);//制作棋盘
	while (1)
	{
    
    
		player(board);//玩家开始下棋
		ret=judgewinner(board);//判断输赢
		if (ret != 'C')
			break;
		computer(board);//电脑开始下棋
		ret=judgewinner(board);//判断输赢
		if (ret != 'C')
			break;
	}
	if (ret == '*')
		printf("The winner is player\n");
	else if (ret == '#')
		printf("The winner is computer\n");
	else if (ret == 'D')
		printf("Player and computer draw\n");

}

1,三子棋需要一个3*3的棋盘
毕竟是个3 * 3的棋盘,可以使用二维数组。
char board[3][3]//这两个行列可以使用宏定义常量,方便延申N子棋。
#define ROW 3
#define COL 3
char board[ROW][COL]

2, 打印三子棋棋盘

大概是这样的
在这里插入图片描述
二维数组的元素也要被定义为空格。在后面玩家或电脑输入后可以被重新定义为*号或#号。

void setboard(char board[ROW][COL], int row, int col)//制作第一个棋盘
{
    
    
	for (int i = 0; i < row; i++)
	{
    
    
		for (int j = 0; j < col; j++)
		{
    
    
			board[i][j] = ' ';//元素被定义为空格
		}
	}
	showboard(board,ROW, COL);//打印棋盘的函数
}
void showboard(char board[ROW][COL], int row, int col)//打印棋盘
{
    
    
	for (int i = 0; i < row; i++)
	{
    
    
		for (int j = 0; j < col; j++)
		{
    
    

			printf(" %c ", board[i][j]);
			if (j < col)
				printf("|");
		}
		if (i < row)
			printf("\n---|---|---|\n");
	}
}

3,玩家落子

就是输入坐标

void player(char board[ROW][COL])//玩家下棋
{
    
    
	int x, y;
	while (1)
	{
    
    
		printf("please input the coordinate:>");
		scanf("%d %d", &x, &y);//输入要落子的坐标
		if (x>=1&&x<=ROW&&y>=1&&y<=COL)//判断该坐标处,是否未被输入过
		{
    
    
			if (board[x - 1][y - 1] != ' ')
				printf("Coordinates occupied,please input again\n");
			else
			{
    
    
				board[x - 1][y - 1] = '*';
				break;
			}
		}
		else
			printf("Coordinate is illegal,please input again\n");//被使用过,重新输入
	}
	//printf("*******************\n");
	printf("Player\n");
	showboard(board, ROW, COL);//打印每次下棋后的棋盘
}

由于玩家并不是程序员不认为,起点是0,所以赋值时要x-1,y-1.。
并且这是多次输入,要保证输入那个坐标处不能已经输入过,就是说要保证该数组元素只能为空格。同时还要保证输入坐标要有效,必须在33的棋盘内,如果两个问题有一个存在,必须要重新输入,所以放入循环内,直到输入正确,才会跳出循环。

4,先不考虑判断输赢,先打印当前棋盘,就是调用showboard(board, ROW, COL);函数,循环打印。

先保证电脑和玩家的棋盘输入输出正确再来判断输赢。

6,电脑开始落子,打印棋盘

暂时先使用随机落子的算法,下次我再写堵截玩家落子的算法

void computer(char board[ROW][COL])//电脑落子
{
    
    
	
	while (1)
	{
    
    
		int x = rand() % ROW;
		int y = rand() % COL;
		if (board[x][y] == ' ')//判断该坐标处,是否未被输入过
		{
    
    
			board[x][y] = '#';
			break;
		}
	}
	printf("Computer\n");
	//printf("*******************\n");
	showboard(board, ROW, COL);//打印每次下棋后的棋盘
}

前面已经使用srand();,保证了随机数

int x = rand() % ROW;
int y = rand() % COL;

X y,为随机数除以排或列的余数,也就是说xy的值必定小于排,列的值,也就保证了xy,为 0,1,2
这也同样保证了由三子棋走向N子棋的条件。
同样得保证电脑落子的坐标处不能已经使用过,必须得保证坐标元素处为空格,才能输入#。并且调用函数打印当前棋盘。

判断棋盘的局面

调用char judgewinner(char board[ROW][COL])函数

char ifdraw(char board[ROW][COL])
{
    
    
	int i;
	for (i = 0; i < ROW; i++)
	{
    
    
		int j;
		for (j = 0; j < COL; j++)
		{
    
    
			if (board[i][j] == ' ')
				return 'C';
		}
	}
	return 'D';
}
char judgewinner(char board[ROW][COL])
{
    
    
	int count;
	//判断一行赢
	for (int i = 0; i < ROW; i++)
	{
    
    
		int j,count=0;
		for (j = 0; j < COL-1; j++)
		{
    
    
			if (board[i][j] != board[i][j + 1])
				break;
			else if (board[i][j] == board[i][j + 1])
				count++;
		}
		if (count == COL - 1)
		{
    
    
			if (board[i][j] == '*')
				return '*';//玩家赢
			else if (board[i][j] == '#')
				return '#';//电脑赢
		}
		if ((count != COL - 1) && (i == ROW - 1))
			return ifdraw(board);//平局
	}
	//判断列赢
	for (int i = 0; i < COL; i++)
	{
    
    
		int j, count = 0;
		for (j = 0; j < ROW - 1; j++)
		{
    
    
			if (board[i][j] != board[i][j + 1])
				break;
			else if (board[i][j] == board[i][j + 1])
				count++;
		}
		if (count == ROW - 1)
		{
    
    
			if (board[i][j] == '*')
				return '*';//玩家赢
			else if (board[i][j] == '#')
				return '#';//电脑赢
		}
		if ((count != ROW - 1) && i == COL - 1)
			return ifdraw(board);//平局
	}
	//判断对角线\赢
	count = 0;
	int i = 0;
	int j;
	while ((count != COL - 1) && (i <ROW-1))
	{
    
    
		j = i;
		if (board[i][j] == board[i + 1][j + 1])
			count++;
		else if (board[i][j] != board[i + 1][j + 1])
			break;
		i++;
		if (count == ROW - 1)
		{
    
    
			if (board[i][j] == '*')
				return '*';//玩家赢
			else if (board[i][j] == '#')
				return '#';//电脑赢
		}
	}
	
	return ifdraw(board);//平局}
		
	
	//对角线/
	count=0;
	i = ROW - 1;
		
	while (i>0)
	{
    
    
		j=ROW-i-1;
		if (board[i][j] == board[i - 1][j + 1])
			count++;
		else if (board[i][j] = board[i - 1][j + 1])
			break;
		i--;
		if (count == COL - 1)
		{
    
    
			if (board[i][j] == '*')
				return '*';//玩家赢
			else if (board[i][j] == '#')
				return '#';//电脑赢
		}
		
	}
	
	return ifdraw(board);//平局
	
}

判断一行或者一列的棋子都相等的情况下,我们使用l两个for循环,我们同时定义一个控制变量。外循环,保证每一个行或每列都能覆盖。内循环来确定每一行或每一列上的元素,相邻之间是否相等?如果相等,count加一,不相等就可以确定,不存在决定当前棋局的条件,直接跳出。同样支持N子棋的判断。

对于左斜线以及右斜线上的三指相的条件,这个就比较简单,,不需要一遍遍的遍历,只需要找到特定的三个元素去判断是否相等即可得出条件。

用这些循环条件来判断,只能得出是否是玩家赢还是电脑赢,但是还需要添加一个函数来判断是否是平局或者棋局未满,可以继续落子。

char ifdraw(char board[ROW][COL])

判断平局或继续落子。

用两个for循环去遍历数组只要判断出有一个元素是空格隔那么就返回c就可以直接得出可以继续落子,就需要返回来D来决定已经平局无法再落子。
因为一旦进入这卡数就表明已经判断出无法决定谁胜或者谁负,只能继续走两条路一就是平局,二就是继续落子

同时,设定了ret来接受judgewinner(char board[ROW][COL])函数的返回值,来判断是否可以继续循环落子。

计算机堵截玩家的算法设计:思路

游戏的规则是行列斜线,三种情况下,只要有一种情况,该线上都归属于三个同样的旗子,即可判断输赢
我们可以考虑循环遍历
依靠循环进入每行每列,每个斜线,进行每个元素的遍历,如果该行该列或该斜线上有两个相同的元素,立马在第三个元素上进行,若无论是否与自己相同.

该思路目前只适用于三字棋,也可延伸到四子棋,4则是两个起步,如果该列该行或该切线上有两个以上的相同元素,就立马在第三或第四个元素中进行落子

以下便是为拆开讲解的全部代码。

主函数界面

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "game.h"
#define ROW 3
#define COL 3
//返回值
//*
//#
//C-继续
//D-平局
void game(void)
{
    
    
	char ret;
	char board[ROW][COL];//创建二维数组
	setboard(board, ROW, COL);//制作棋盘
	while (1)
	{
    
    
		player(board);//玩家开始下棋
		ret=judgewinner(board);//判断输赢
		if (ret != 'C')
			break;
		computer(board);//电脑开始下棋
		ret=judgewinner(board);//判断输赢
		if (ret != 'C')
			break;
	}
	if (ret == '*')
		printf("The winner is player\n");
	else if (ret == '#')
		printf("The winner is computer\n");
	else if (ret == 'D')
		printf("Player and computer draw\n");

}
void option(int input)
{
    
    
	switch (input)//分支语句
	{
    
    
	case 1:
		game();
		break;
	case 0:
		printf("Logon out the game\n");
		break;
	default:
		printf("Input error,please input again\n");
		break;
	}
}
void menu(void)
{
    
    
	printf("Welcome to game\n");
	printf("\n");
	printf("****************\n");
	printf("*----1.play----*\n");
	printf("*----0.exit----*\n");
	printf("****************\n");
}
int main(void)
{
    
    
	int input;
	srand((unsigned int)time(NULL));
	do
	{
    
    
		menu();//打印游戏菜单
		printf("please input option(1/0):>");
		scanf("%d", &input);
		option(input);//选项判断
	} while (input);
}

game.c

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "game.h"
//void game(void)
//{
    
    
//	char board[ROW][COL];//创建二维数组
//	setboard(board, ROW, COL);//制作棋盘
//	player(board);//玩家开始下棋
//
//	computer(board);//电脑开始下棋
//
//}
void setboard(char board[ROW][COL], int row, int col)//制作第一个棋盘
{
    
    
	for (int i = 0; i < row; i++)
	{
    
    
		for (int j = 0; j < col; j++)
		{
    
    
			board[i][j] = ' ';
		}
	}
	showboard(board,ROW, COL);
}
void showboard(char board[ROW][COL], int row, int col)//打印棋盘
{
    
    
	for (int i = 0; i < row; i++)
	{
    
    
		for (int j = 0; j < col; j++)
		{
    
    

			printf(" %c ", board[i][j]);
			if (j < col)
				printf("|");
		}
		if (i < row)
			printf("\n---|---|---|\n");
	}
}
void player(char board[ROW][COL])//玩家下棋
{
    
    
	int x, y;
	while (1)
	{
    
    
		printf("please input the coordinate:>");
		scanf("%d %d", &x, &y);//输入要落子的坐标
		if (x>=1&&x<=ROW&&y>=1&&y<=COL)//判断该坐标处,是否未被输入过
		{
    
    
			if (board[x - 1][y - 1] != ' ')
				printf("Coordinates occupied,please input again\n");
			else
			{
    
    
				board[x - 1][y - 1] = '*';
				break;
			}
		}
		else
			printf("Coordinate is illegal,please input again\n");//被使用过,重新输入
	}
	//printf("*******************\n");
	printf("Player\n");
	showboard(board, ROW, COL);//打印每次下棋后的棋盘
}
void computer(char board[ROW][COL])//电脑落子
{
    
    
	
	while (1)
	{
    
    
		int x = rand() % ROW;
		int y = rand() % COL;
		if (board[x][y] == ' ')//判断该坐标处,是否未被输入过
		{
    
    
			board[x][y] = '#';
			break;
		}
	}
	printf("Computer\n");
	//printf("*******************\n");
	showboard(board, ROW, COL);//打印每次下棋后的棋盘
}
char ifdraw(char board[ROW][COL])
{
    
    
	int i;
	for (i = 0; i < ROW; i++)
	{
    
    
		int j;
		for (j = 0; j < COL; j++)
		{
    
    
			if (board[i][j] == ' ')
				return 'C';
		}
	}
	return 'D';
}
char judgewinner(char board[ROW][COL])
{
    
    
	int count;
	//判断一行赢
	for (int i = 0; i < ROW; i++)
	{
    
    
		int j,count=0;
		for (j = 0; j < COL-1; j++)
		{
    
    
			if (board[i][j] != board[i][j + 1])
				break;
			else if (board[i][j] == board[i][j + 1])
				count++;
		}
		if (count == COL - 1)
		{
    
    
			if (board[i][j] == '*')
				return '*';//玩家赢
			else if (board[i][j] == '#')
				return '#';//电脑赢
		}
		if ((count != COL - 1) && (i == ROW - 1))
			return ifdraw(board);//平局
	}
	//判断列赢
	for (int i = 0; i < COL; i++)
	{
    
    
		int j, count = 0;
		for (j = 0; j < ROW - 1; j++)
		{
    
    
			if (board[i][j] != board[i][j + 1])
				break;
			else if (board[i][j] == board[i][j + 1])
				count++;
		}
		if (count == ROW - 1)
		{
    
    
			if (board[i][j] == '*')
				return '*';//玩家赢
			else if (board[i][j] == '#')
				return '#';//电脑赢
		}
		if ((count != ROW - 1) && i == COL - 1)
			return ifdraw(board);//平局
	}
	//判断对角线\赢
	count = 0;
	int i = 0;
	int j;
	while ((count != COL - 1) && (i <ROW-1))
	{
    
    
		j = i;
		if (board[i][j] == board[i + 1][j + 1])
			count++;
		else if (board[i][j] != board[i + 1][j + 1])
			break;
		i++;
		if (count == ROW - 1)
		{
    
    
			if (board[i][j] == '*')
				return '*';//玩家赢
			else if (board[i][j] == '#')
				return '#';//电脑赢
		}
	}
	
	return ifdraw(board);//平局}
		
	
	//对角线/
	count=0;
	i = ROW - 1;
		
	while (i>0)
	{
    
    
		j=ROW-i-1;
		if (board[i][j] == board[i - 1][j + 1])
			count++;
		else if (board[i][j] = board[i - 1][j + 1])
			break;
		i--;
		if (count == COL - 1)
		{
    
    
			if (board[i][j] == '*')
				return '*';//玩家赢
			else if (board[i][j] == '#')
				return '#';//电脑赢
		}
		
	}
	
	return ifdraw(board);//平局
	
}

game.h

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
void game(void);//三子棋游戏
void setboard(char board[ROW][COL], int row, int col);//创建棋盘
void showboard(char board[ROW][COL], int row, int col);//打印、展示棋盘
void player(char board[ROW][COL]);//玩家落子
void computer(char board[ROW][COL]);//电脑落子
char judgewinner(char board[ROW][COL]);//判断输赢
char ifdraw(char board[ROW][COL]);//判断是否平局

猜你喜欢

转载自blog.csdn.net/weixin_52199109/article/details/113096617