【全网最强C语言学习】五子棋游戏

目录

一、前言

二、头文件

三、menu菜单函数

四、初始化棋盘Initboard函数

五、显示棋盘Displayboard函数

六、落子函数

七、判断输赢ifwin

八、人机、人人模式的选择

九、作者遇到的坑点

十、完整的代码


一、前言

本文将先介绍五子棋运行所需要的函数,最后串联成完整代码。

我们需要实现的功能有:1.菜单menu函数 

                                        2.初始化棋盘Initboard函数

                                        3.显示棋盘Displayboard函数

                                        4.实现人机、人人模式的选择

                                        5.落子函数 playermove  computermove

                                        6.判断输赢ifwin函数

 先来看看运行效果吧!


二、头文件

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
#define	ROW 10  //定义棋盘的宽
#define COL 10  //定义棋盘的长
                //定义常量方便全局的修改
void Initboard(char board[ROW][COL], int row, int col);
//初始化棋盘
void Displayboard(char board[ROW][COL], int row, int col);
//展示棋盘
void Playermove_1(char board[ROW][COL], int row, int col,int*px,int *py);
//玩家一下棋
void Playermove_2(char board[ROW][COL], int row, int col,int*px, int *py);
//玩家二下棋
void computermove(char board[ROW][COL], int row, int col);
//电脑下棋
void game1(char board[ROW][COL], int row, int col);
//人机模式
void game2(char board[ROW][COL], int row, int col);
//人人模式
int Ifwin(char board[ROW][COL], int row, int col, int x, int y);
//判断输赢
int check_x(char board[ROW][COL], int row, int col, int x, int y);
//判断竖直五子
int check_y(char board[ROW][COL], int row, int col, int x, int y);
//判断水平五子
int check_xy_up(char board[ROW][COL], int row, int col, int x, int y);
//判断斜上五子
int check_xy_down(char board[ROW][COL], int row, int col, int x, int y);
//判断斜下五子

三、menu菜单函数

void menu()
{   //完成菜单的初始化
	printf("***********************\n");
	printf("***********************\n");
	printf("*****1.play  0.exit****\n");
	printf("***********************\n");
	printf("***********************\n");
	printf("请输入:");
}

很简单,就不多说了


四、初始化棋盘Initboard函数

初始化棋盘,为数组一一存入空格

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

五、显示棋盘Displayboard函数

打印简单的方格线,并打印数据内容

void Displayboard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (j = 0; j < col; j++)//打印横向y坐标
	{
		if (j == 0)//考虑到x轴所占的一格
		{
			printf("  %d  ", j + 1);
			
		}
		else
		{
			printf(" %d  ", j + 1);
			
		}
	}
	printf("\n");
	for (i = 0; i < row; i++)//打印数据
	{

		for (j = 0; j < col; j++)
		{
			
			if (j == 0)//顺带打印竖向x坐标
			{
				printf("%2d",i+1);//%md表示域宽为m
				printf("  %c ",board[i][j]);
				
			}
			else
			{
				printf(" %c ", board[i][j]);
			}
			
			if (j < col - 1)
				printf("|");
		}
		printf("\n");

		//打印分割行
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				if (j == 0)//同样考虑到y轴
					printf("   ---");
				else
					printf("---");


				if (j < col - 1)
					printf("|");

			}
			printf("\n");

		}
	}

}

六、落子函数

玩家一落子——playermove_1

void Playermove_1(char board[ROW][COL], int row, int col, int *px, int*py)//ROW可以省,COL不行
{
	int x = *px;
	int y = *py;
	while (1)
	{
		
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入坐标的合法性
		{
			if (board[x -1][y- 1] == ' ')//保证落子点为空
			{							 
				board[x-1 ][y -1] = '*';
				*px = x; *py = y;//如果开始xy输入不合法,则要对外部xy修改,所以选择传址操作
				break;
			}
			else
			{
				printf("你不能在此处落子\n");
				printf("玩家1落子,请重新输入x y坐标: ");
				scanf("%d%d", &x, &y);
			}
		}
		else
		{
			printf("输入坐标不合法\n");
			printf("玩家落子,请重新输入x y坐标: ");
			scanf("%d%d", &x, &y);
		}
	}

}

玩家2落子完全相同,就不赘叙了

电脑落子

void computermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	
    //rand函数的使用需要srand函数的初始化,但srand不可以被重复调用,所以放在外部
	while (1)
	{
		x = rand() % ROW;
		y = rand() % COL;
		if (board[x][y] == ' ')//x的范围在0~row-1,所以这里x不用-1了
		{
			board[x][y] = '#';
			break;
		}
	}

}

七、判断输赢ifwin

根据我们下五子棋的经验,能获胜的地方必定是最后落子的水平线、竖直线、和两个斜对角线,我们只需对其进行检索即可。ifwin的返回值决定之后的switch语句

弱弱的说一句,虽然看起来多,但很多都是重复的。若要优化就使用函数指针

int Ifwin(char board[ROW][COL], int row, int col, int x, int y)
{
	int ret;
	{
		ret = check_x(board, row, col, x, y);
		if (ret >= 5)
			return 0;

		ret = check_y(board, row, col, x, y);
		if (ret >= 5)
			return 0;
		ret = check_xy_up(board, row, col, x, y);
		if (ret >= 5)
			return 0;
		ret = check_xy_down(board, row, col, x, y);
		if (ret >= 5)
			return 0;
	}

		return 3;
}



int check_x(char board[ROW][COL], int row, int col, int x, int y)//检查x轴竖直方向
{
	int sum = 1;
	int old_x = x;
	while (x < row  && board[x - 1][y - 1] == board[x][y - 1])
	{
		sum++;
		x++;
	}
	x = old_x;
	while (x-2>= 0 && board[x - 1][y - 1] == board[x - 2][y - 1] )
	{
		sum++;
		x--;
	}
	return sum;
}



int check_y(char board[ROW][COL], int row, int col, int x, int y)//检查y轴水平方向
{
	int sum = 1;
	int old_y = y;
	while (y<col && board[x-1][y-1] == board[x-1][y]  )
	{
		sum++;
		y++;
	}
	y = old_y;
	while (y-2 >= 0 && board[x-1][y-1] == board[x-1][y -2]  )
	{
		sum++;
		y--;
	}
	return sum;
}



int check_xy_up(char board[ROW][COL], int row, int col, int x, int y)//检查斜上45度
{
	int sum = 1;
	int old_x = x;
	int old_y = y;
	while (x<row &&  y - 2 >= 0 && board[x - 1][y - 1] == board[x][y - 2])
	{
		sum++;
		x++;
		y--;
	}
	x = old_x;
	y = old_y;
	while (x - 2 >= 0 && y <col && board[x - 1][y - 1] == board[x - 2][y])
	{
		sum++;
		x--;
		y++;
	}
	return sum;
}



int check_xy_down(char board[ROW][COL], int row, int col, int x, int y)//检查斜下45度
{
	int sum = 1;
	int old_x = x;
	int old_y = y;
	while (x<row && y <col && board[x - 1][y - 1] == board[x][y])
	{
		sum++;
		x++;
		y++;
	}
	x = old_x;
	y = old_y;
	while (board[x-1][y-1] == board[x -2][y-2 ] && x-2>=0  && y-2 >=0)
	{
		sum++;
		x--;
		y--;
	}
	return sum;
}


八、人机、人人模式的选择

初始选择界面

void game()
{
	int input;
	char board[ROW][COL] = { 0 };
	Initboard(board, ROW, COL);
	//初始化棋盘
	Displayboard(board, ROW, COL);
	//展示棋盘
	printf("请选择模式:1.人机;2.玩家对战\n");
	printf("请选择:");
	

	do{
		scanf("%d", &input);
		printf("\n");
		switch (input)
		{
		case 1:printf("游戏模式1开始!(注意:竖为x轴,横为y轴)\n");  game1(board, ROW, COL); break;
		case 2:printf("游戏模式2开始!(注意:竖为x轴,横为y轴)\n"); ; game2(board, ROW, COL); break;
		default:printf("请重新输入\n"); break;
		}
	} while (input != 1 && input != 2);//do while语句在输入错误时反复输入
}

game1的具体实现

void game1(char board[ROW][COL], int row, int col)
{
	srand((unsigned int)time(NULL));//srand只要设置一次就可以,所以要放在while循环外
	while (1)
	{
		int ret;
		int count = 0;
		int flag = 0;
		//判读玩家的下棋
		int x; int y;
		printf("玩家落子,请依次输入x y坐标: ");
		scanf("%d%d", &x, &y);
		Playermove_1(board, row, col,&x, &y);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)//全下满则认为平局
			ret = 1;
		else 
		    ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("玩家获胜\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;
		}
		if (flag == 1)//用flag跳出while循环
			break;


		//判断计算机的下棋
		computermove(board, row, col);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)
			ret = 1;
		else
			ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("电脑获胜\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;

		}
		if (flag == 1)
			break;

	}


}

作者觉得写的是挺啰嗦,欢迎留言建议。game2和game1玩家一的内容很相近,就不赘述


九、作者遇到的坑点

1.输入的坐标和存在数组里的下标有减一的关系,在写的时候不要写忘记了

2.传址操作才能改变函数外的变量值


十、完整的代码

头文件就省了

int main()
{
	int input;
	do{
		system("cls");//清屏
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("游戏开始\n\n");  game(); break;
		case 0:
			printf("退出游戏\n"); break;
		default:
			printf("请重新输入\n"); break;
		}
		
		Sleep(3000);//暂停3秒
	} while (input);//do while语句实现可以反复玩


	return 0;
}





void menu()
{   //完成菜单的初始化
	printf("***********************\n");
	printf("***********************\n");
	printf("*****1.play  0.exit****\n");
	printf("***********************\n");
	printf("***********************\n");
	printf("请输入:");
}





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





void Displayboard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (j = 0; j < col; j++)//打印横向y坐标
	{
		if (j == 0)//考虑到x轴所占的一格
		{
			printf("  %d  ", j + 1);
			
		}
		else
		{
			printf(" %d  ", j + 1);
			
		}
	}
	printf("\n");
	for (i = 0; i < row; i++)//打印数据
	{

		for (j = 0; j < col; j++)
		{
			
			if (j == 0)//顺带打印竖向x坐标
			{
				printf("%2d",i+1);//%md表示域宽为m
				printf("  %c ",board[i][j]);
				
			}
			else
			{
				printf(" %c ", board[i][j]);
			}
			//数字表示坐标
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		//打印分割行
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				if (j == 0)//同样考虑到y轴
					printf("   ---");
				else
					printf("---");


				if (j < col - 1)
					printf("|");

			}
			printf("\n");//别忘记这里也要换行

		}
	}

}





void game()
{
	int input;
	char board[ROW][COL] = { 0 };
	Initboard(board, ROW, COL);
	//初始化棋盘
	Displayboard(board, ROW, COL);
	//展示棋盘
	printf("请选择模式:1.人机;2.玩家对战\n");
	printf("请选择:");
	

	do{
		scanf("%d", &input);
		printf("\n");
		switch (input)
		{
		case 1:printf("游戏模式1开始!(注意:竖为x轴,横为y轴)\n");  game1(board, ROW, COL); break;
		case 2:printf("游戏模式2开始!(注意:竖为x轴,横为y轴)\n"); ; game2(board, ROW, COL); break;
		default:printf("请重新输入\n"); break;
		}
	} while (input != 1 && input != 2);//do while语句在输入错误时反复输入
}




void game1(char board[ROW][COL], int row, int col)
{
	srand((unsigned int)time(NULL));//srand只要设置一次就可以,所以要放在while循环外
	while (1)
	{
		int ret;
		int count = 0;
		int flag = 0;
		//判读玩家的下棋
		int x; int y;
		printf("玩家落子,请依次输入x y坐标: ");
		scanf("%d%d", &x, &y);
		Playermove_1(board, row, col,&x, &y);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)//全下满则认为平局
			ret = 1;
		else 
		    ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("玩家获胜\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;
		}
		if (flag == 1)//用flag跳出while循环
			break;


		//判断计算机的下棋
		computermove(board, row, col);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)
			ret = 1;
		else
			ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("电脑获胜\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;

		}
		if (flag == 1)
			break;

	}


}






void game2(char board[ROW][COL], int row, int col)
{
	while (1)
	{
		int ret;
		int count = 0;
		int flag = 0;
		int x; int y;
		//判读玩家1的下棋
		printf("玩家1落子,请输入坐标:(注意:竖为x轴,横为y轴)");
		scanf("%d%d", &x, &y);
		Playermove_1(board, row, col, &x, &y);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)
			ret = 1;
		else
			ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("玩家1获胜\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;
		}
		if (flag == 1)
			break;


		//判断玩家2的下棋
		printf("玩家2落子,请输入坐标:(注意:竖为x轴,横为y轴)");
		scanf("%d%d", &x, &y);
		Playermove_2(board, row, col, &x, &y);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)
			ret = 1;
		else
			ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("玩家2获胜\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;
		}
		if (flag == 1)
			break;
		
	}


}





void Playermove_1(char board[ROW][COL], int row, int col, int *px, int*py)//ROW可以省,COL不行
{
	int x = *px;
	int y = *py;
	while (1)
	{
		
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入坐标的合法性
		{
			if (board[x -1][y- 1] == ' ')//保证落子点为空
			{							 
				board[x-1 ][y -1] = '*';
				*px = x; *py = y;//如果开始xy输入不合法,要对外部xy修改,所以要传址操作
				break;
			}
			else
			{
				printf("你不能在此处落子\n");
				printf("玩家1落子,请重新输入x y坐标: ");
				scanf("%d%d", &x, &y);
			}
		}
		else
		{
			printf("输入坐标不合法\n");
			printf("玩家落子,请重新输入x y坐标: ");
			scanf("%d%d", &x, &y);
		}
	}

}





void Playermove_2(char board[ROW][COL], int row, int col, int *px, int*py)
{
	int x = *px;
	int y = *py;
	while (1)
	{
		
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入坐标的合法性
		{
			if (board[x - 1][y - 1] == ' ')//保证落子点为空
			{
				board[x - 1][y - 1] = '#';
				*px = x; *py = y;
				break;
			}
			else
			{
				printf("你不能在此处落子\n");
				printf("玩家2落子,请重新输入x y坐标: ");
				scanf("%d%d", &x, &y);
			}
		}
		else
		{
			printf("输入坐标不合法\n");
			printf("玩家落子,请重新输入x y坐标: ");
			scanf("%d%d", &x, &y);
		}
	}

}






void computermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	

	while (1)
	{
		x = rand() % ROW;
		y = rand() % COL;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}

}




int Ifwin(char board[ROW][COL], int row, int col, int x, int y)
{
	int ret;
	{
		ret = check_x(board, row, col, x, y);
		if (ret >= 5)
			return 0;

		ret = check_y(board, row, col, x, y);
		if (ret >= 5)
			return 0;
		ret = check_xy_up(board, row, col, x, y);
		if (ret >= 5)
			return 0;
		ret = check_xy_down(board, row, col, x, y);
		if (ret >= 5)
			return 0;
	}

		return 3;
}



int check_x(char board[ROW][COL], int row, int col, int x, int y)//检查x轴竖直方向
{
	int sum = 1;
	int old_x = x;
	while (x < row  && board[x - 1][y - 1] == board[x][y - 1])
	{
		sum++;
		x++;
	}
	x = old_x;
	while (x-2>= 0 && board[x - 1][y - 1] == board[x - 2][y - 1] )
	{
		sum++;
		x--;
	}
	return sum;
}



int check_y(char board[ROW][COL], int row, int col, int x, int y)//检查y轴水平方向
{
	int sum = 1;
	int old_y = y;
	while (y<col && board[x-1][y-1] == board[x-1][y]  )
	{
		sum++;
		y++;
	}
	y = old_y;
	while (y-2 >= 0 && board[x-1][y-1] == board[x-1][y -2]  )
	{
		sum++;
		y--;
	}
	return sum;
}



int check_xy_up(char board[ROW][COL], int row, int col, int x, int y)//检查斜上45度
{
	int sum = 1;
	int old_x = x;
	int old_y = y;
	while (x<row &&  y - 2 >= 0 && board[x - 1][y - 1] == board[x][y - 2])
	{
		sum++;
		x++;
		y--;
	}
	x = old_x;
	y = old_y;
	while (x - 2 >= 0 && y <col && board[x - 1][y - 1] == board[x - 2][y])
	{
		sum++;
		x--;
		y++;
	}
	return sum;
}



int check_xy_down(char board[ROW][COL], int row, int col, int x, int y)//检查斜下45度
{
	int sum = 1;
	int old_x = x;
	int old_y = y;
	while (x<row && y <col && board[x - 1][y - 1] == board[x][y])
	{
		sum++;
		x++;
		y++;
	}
	x = old_x;
	y = old_y;
	while (board[x-1][y-1] == board[x -2][y-2 ] && x-2>=0  && y-2 >=0)
	{
		sum++;
		x--;
		y--;
	}
	return sum;
}

如果对你有帮助和启发,作者感到很高兴。如果有好的建议,欢迎留言。如果发现错误,欢迎指正。新手上路,多多指点 

猜你喜欢

转载自blog.csdn.net/whc18858/article/details/119981279