Bootstrap

游戏五子棋(c语言)

一、项目背景

​ 五子棋是一种两人对弈的纯策略型棋类益智游戏,容易上手,两人对局,各执一色,轮流下一子,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜。本章将使用C语言和OpenGL图形编程技术来实现一个简单的五子棋游戏。

二、设计目的

  • 如何通过键盘操作选择菜单
  • 如何设计五子棋的下棋逻辑
  • 如何使用OpenGL进行棋局绘图操作
  • 如何在OpenGL下实现鼠标键盘的操控功能
  • 如何显示右键菜单,并实现悔棋、重玩等辅助功能

三、项目功能需求

1、欢迎界面

  • 玩家可在欢迎界面中选择进入游戏或者直接退出。

2、下棋操作

  • 在棋盘中点击鼠标进行下棋,双方轮流下子。

3、重玩功能

  • 玩家结束游戏后需要重开一局时,使用该功能可重新进入新一轮游戏。

4、悔棋功能

  • 玩家在游戏时难免会产生失误,那时可以使用该功能进行悔棋操作。

5、胜负判断

  • 程序可以对下棋结果进行判断,然后显示获胜玩家的信息。

四、系统的功能结构图

在这里插入图片描述

五、功能模块介绍

1、用户界面模块

  • 用于实现用户界面的显示,提示用户操作的信息,实现更好的交互性。

2、下棋操作模块

  • 五子棋游戏的核心模块,用于响应用户的鼠标点击落子处理,实现下棋的逻辑处理

3、图形描画模块

  • 提供描画函数,负责棋盘,棋子等图形的显示

4、菜单控制模块

  • 通过鼠标右键点击棋盘,可以显示菜单栏,实现悔棋、重玩等功能。

六、详细设计

1、主函数

首先初始化OpenGL描画库 资源,然后进入的是游戏欢迎界面,由玩家选择是否进入游戏,或者直接退 出。

处理流程如图

在这里插入图片描述

2、界面显示模块

功能设计

  • 界面显示模块用于显示欢迎界面、游戏帮助界面、玩家获胜界面、游戏结束界面。

3、下棋操作模块

功能设计

  • 通过鼠标的点击操作来实现落子的功能,并把落子的信息保存到棋局数组。
  • 每次落子处理的同时,都要进行胜负判定,来决定是否一方胜出,棋局结束。

下棋操作流程图

在这里插入图片描述

4、图形描画模块

功能设计

  • 实现了游戏棋盘和棋子的描画和显示。
  • 每一次用户的落子操作之后,都会进行一次棋盘和棋子的重绘。
  • 通过调用OpenGL的基本描画函数,可以实现将棋局信息进行描画,并显示到屏幕上。

5、功能菜单模块

功能设计

  • 定义鼠标点击右键后会出现下棋时需要使用的功能。
  • 功能包括重新开始游戏,悔棋,中途退出。

七、代码

#include<stdio.h>    /*包含C语言的基本输入输出函数*/
#include<conio.h>    /*与GotoXY函数的定义有关*/
#include<windows.h>  /*调用system函数*/
#include <GL/glut.h> /*OpenGL操作函数*/
#include<math.h>     /*调用qsort函数*/

/*宏定义*/
#define WINDOW_SIZE 600 /*游戏界面的大小*/
#define WINDOW_POS	100 /*游戏界面的位置(左上角)*/
#define ENTER 13
#define ESC 27
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define START_POS 13
#define QUIT_POS 16

/*全局变量定义*/
int aiStep[250];    /*存储之前下的棋子*/
int iNum = 0;       /*下棋的步数*/
GLint iPlayer = 1;  /*黑棋为1,白棋为-1*/
GLint iEnd = 0;     /*是否结束*/
GLint aiBoard[15][15];/*记录棋盘棋子,0表示没有棋子,1表示黑子,-1表示白子*/
struct Point
{
	int x;
	int y;
}stPoint;

/*函数声明*/
void GotoXY(int x, int y);
int ChooseArrow();
int ShowWelcome();
void ShowEnd();
void ShowGuide();
void ShowWinner();
int JudgeWin(int x, int y);
void TransPos(int *x, int *y);
void DrawChess(int x, int y, int iColor);
void NewGame();
void ManageItem(int n);
void DrawBoard();
void DisplayGL();
void CtrlKeyboard(unsigned char iKey, int x, int y);
void CtrlMouse(int iButton, int iState, int x, int y);
void CtrlMenu();

/*光标移动操作*/
void GotoXY(int x, int y)
{
	COORD c;
	c.X = 2 * x;
	c.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
/*选择键面操作*/
int ChooseArrow()
{
	char cButton;       /*键盘敲下的键值*/
	int iStart = -1;    /*0表示退出游戏,1表示开始游戏*/
	/*若是按下退出或开始游戏就退出循环*/
	while (iStart != 0 && iStart != 1)
	{
		cButton = getch();
		/*若是up和down就进行光标移动操作*/
		if (cButton == UP || cButton == DOWN)
		{
			if (stPoint.y == START_POS)
			{
				stPoint.y = QUIT_POS;
				GotoXY(10, START_POS);
				printf("     ");
				GotoXY(10, QUIT_POS);
				printf("——>");
				GotoXY(12, QUIT_POS);
			}
			else if (stPoint.y == QUIT_POS)
			{
				stPoint.y = START_POS;
				GotoXY(10, QUIT_POS);
				printf("     ");
				GotoXY(10, START_POS);
				printf("——>");
				GotoXY(12, START_POS);
			}
		}
		/*按下esc键或enter退出游戏*/
		if ((cButton == START_POS && stPoint.y == QUIT_POS) || cButton == ESC)
		{
			iStart = 0;
			break;
		}
		/*开始游戏*/
		if (cButton == START_POS && stPoint.y == START_POS)
		{
			iStart = 1;
			break;
		}
	}
	return iStart;
}
/*欢迎键面*/
int ShowWelcome()
{
	int iStart = -1;    /*0表示退出游戏,1表示开始游戏*/
	system("color 3F");
	GotoXY(14, 1);
	printf("Welcome to play fivechess");
	GotoXY(17, 7);
	printf("MAIN MENU");
	GotoXY(15, START_POS);
	printf("***START GAME***");
	GotoXY(15, QUIT_POS);
	printf("***QUIT  GAME***");
	GotoXY(10, START_POS);
	printf("——>");
	stPoint.x = 15;
	stPoint.y = START_POS;
	GotoXY(12, START_POS);
	iStart = ChooseArrow();
	return iStart;
}
/*游戏进行时的键面*/
void ShowGuide()
{
	system("cls");
	system("color 4F");
	GotoXY(6, 5);
	printf("BLACK");
	GotoXY(6, 9);
	printf("PLAYER");
	GotoXY(19, 7);
	printf("VS");
	GotoXY(31, 5);
	printf("WHITE");
	GotoXY(31, 9);
	printf("PLAYER");
	GotoXY(6, 18);
	printf("1: You Can Click Right Button to Play Again, Undo or Exit!");
	GotoXY(6, 20);
	printf("2: You can use ESC key to exit the game too!");
}
/*结束键面*/
void ShowEnd()
{
	system("cls");
	system("color 6F");
	GotoXY(16, 3);
	printf("GAME OVER!!!");
	GotoXY(1, 23);
}
/*显示赢家*/
void ShowWinner()
{
	system("cls");
	GotoXY(15, 8);
	printf("congratulations!!!");
	GotoXY(12, 13);
	if (iPlayer == 1)
	{
		system("color 0F");
		printf("BLACK PLAYER WIN THE GAME!!!");
	}
	else
	{
		system("color 2F");
		printf("WHITE PLAYER WIN THE GAME!!!");
	}
}
/*判断玩家是否胜利*/
int JudgeWin(int x, int y)
{
	int aiDir[4][2] = { 0, 1, 1, 0, 1, 1, 1, -1 };
	for (int i = 0; i<4; ++i)
	{
		/*连续棋子的数目*/
		int iTotal = 1;
		for (int j = 1; aiBoard[x][y] == aiBoard[x + j*aiDir[i][0]][y + j*aiDir[i][1]]; ++j)
			++iTotal;
		for (int j = 1; aiBoard[x][y] == aiBoard[x - j*aiDir[i][0]][y - j*aiDir[i][1]]; ++j)
			++iTotal;
		if (iTotal >= 5) return 1;
	}
	return 0;
}
/*把屏幕坐标转换成棋盘上的坐标*/
void TransPos(int *x, int *y)
{
	*y = WINDOW_SIZE - *y;
	*x = (*x << 4) / (WINDOW_SIZE*1.0) - 0.5;
	*y = (*y << 4) / (WINDOW_SIZE*1.0) - 0.5;
}
/*画棋子(即画一个圆)*/
void DrawChess(int x, int y, int iColor)
{
	if (iColor == 1)
		glColor3f(0, 0, 0);
	else
		glColor3f(1, 1, 1);
	glBegin(GL_TRIANGLE_FAN);
	for (int i = 0; i < 360; i++)
		glVertex2f(0.37*cos(i*1.0) + x + 1, 0.37*sin(i*1.0) + y + 1);/*圆弧上各个点的坐标*/
	glEnd();
}
/*开始新一局游戏时用来初始化数据*/
void NewGame()
{
	ShowGuide();
	iNum = 0;
	iPlayer = 1;
	iEnd = 0;
	memset(aiBoard, 0, sizeof(aiBoard));
}
/*绘画opengl键面*/
void DrawBoard()
{
	glClearColor(0.1, 0.2, 0.3, 0);
	glMatrixMode(GL_PROJECTION); /*对投影相关进行操作,也就是把物体投影到一个平面上*/
	glOrtho(0, 16, 0, 16, -1, 1);
	/*画棋盘的线*/
	static GLint vertices[120];
	int i, j;
	for (i = 0; i<15; i++)
	{
		j = i << 2;
		vertices[j] = i + 1;
		vertices[j + 1] = 1;
		vertices[j + 2] = i + 1;
		vertices[j + 3] = 15;
		vertices[j + 60] = 1;
		vertices[j + 61] = i + 1;
		vertices[j + 62] = 15;
		vertices[j + 63] = i + 1;
	}
	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(2, GL_INT, 0, vertices);
}
void DisplayGL()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1, 1, 1);
	/*画棋盘*/
	glDrawArrays(GL_LINES, 0, 60);
	/*画棋子*/
	for (int i = 0; i<15; i++)
	{
		for (int j = 0; j<15; j++)
		{
			if (aiBoard[i][j])
				DrawChess(i, j, aiBoard[i][j]);
		}
	}
	glFlush();
}
/*鼠标操作函数*/
void CtrlMouse(int iButton, int iState, int x, int y)
{
	switch (iButton)
	{
	case GLUT_LEFT_BUTTON:
		if (!iEnd)
		{
			TransPos(&x, &y);
			if (aiBoard[x][y]) break;
			aiBoard[x][y] = iPlayer;
			/*将落下的棋子记录进step数组*/
			aiStep[iNum++] = x * 100 + y;
			if (JudgeWin(x, y))
			{
				iEnd = 1;
				ShowWinner();
			}
			/*交换选手*/
			iPlayer = -iPlayer;
			glutPostRedisplay();
		}
		break;
	case GLUT_RIGHT_BUTTON:
		NewGame();
		glutPostRedisplay();
		break;
	}
}
/*键盘操作函数*/
void CtrlKeyboard(unsigned char cKey, int x, int y)
{
	if(cKey == ESC)
	{
		ShowEnd();
		exit(0);
	}
}
/*右键菜单栏选项*/
void CtrlMenu()
{
	int newGameMenu = glutCreateMenu(ManageItem);
	glutAddMenuEntry("Play Again", 1);
	glutAddMenuEntry("Undo", 2);
	glutAddMenuEntry("Exit", 3);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
}
/*右键菜单操作*/
void ManageItem(int iNumber)
{
	switch (iNumber)
	{
	case 1:
		NewGame();
		break;
	case 2:
		if (iNum == 0) break;
		int iPrev = aiStep[iNum - 1];
		/*将刚才的落子从记录中抹去*/
		iNum--;
		aiBoard[iPrev / 100][iPrev % 100] = 0;
		iPlayer = -iPlayer;
		break;
	case 3:
		ShowEnd();
		exit(0);
		break;
	}
	glutPostRedisplay();
}
int main(int argc, char **argv)
{
	int iStart = -1;    /*0表示退出游戏,1表示开始游戏*/
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowSize(WINDOW_SIZE, WINDOW_SIZE);
	glutInitWindowPosition(WINDOW_POS, WINDOW_POS);
	iStart = ShowWelcome();/*进入游戏欢迎键面*/
	if (iStart)/*是否进入游戏*/
	{
		ShowGuide();
		glutCreateWindow("fivechess");
		DrawBoard();
		CtrlMenu();
		NewGame();
		glutDisplayFunc(DisplayGL);
		glutKeyboardFunc(CtrlKeyboard);
		glutMouseFunc(CtrlMouse);
		glutMainLoop();
	}
	ShowEnd();
	return 0;
}
;