五子棋项目总结

花时一个礼拜,终于做出了自己想要的五子棋游戏,虽然感觉还是有些地方不够完善,但是作为自己完成的第一个完整的项目,还是有些成就感的,特别在人机方面花费了自己蛮多心力,还好自己的人机也不算太笨,第一个项目和答辩也算圆满完成了!

在做五子棋的过程中,学习了easyx和人工智能部分的算法,下面是项目截图。

 

 

以下是代码,注释也写得较为清除。

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#include<graphics.h>
#include<conio.h>
#include<algorithm>
#pragma warning(disable:4996)
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")

using namespace std;
int Nowx, Nowy;//双人游戏当前下的棋子位置
int Playerx, Playery;//人机模式玩家当前下的棋子位置
int mp[16][16];//记录棋子位置状态
int Next[4][2] = { 0,1,1,0,1,1,-1,1 };
void CreatMenu();
int PlayBChess();
void DoubleGame();
void Play_Bgm();
int nx, ny;//棋子移动的当前位置
stack<int>ChessX;
stack<int>ChessY;
int RtimesW = 1,RtimesB = 1;//设置悔棋次数为1
int Mtimes = 2;//设置人机对战悔棋步数为两步
int flagW= 0;
int flagB = 0;
int stepPlayer = 0;//记录玩家赢棋步数
/*struct stone
{
	int x, y, lianzi, dx, dy;
};*/

/*typedef struct node//用链表来存储每一局人机对战玩家获胜的步数
{
	int data;
	node* next;
}step;*/
//step* head;

void ClearStack()//清空栈
{
	while (!ChessX.empty()) {
		ChessX.pop();
		ChessY.pop();
	}
}

void initmap()//地图初始化
{
	stepPlayer = 0;
	RtimesW = 1, RtimesB = 1;
	Mtimes = 2;
	ClearStack();//重新游戏时清空栈
	stepPlayer = 0;
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 16; j++) {
			mp[i][j] = 0;
		}
	}
}

int AllBoard()//判断棋盘是否下满
{
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 16; j++) {
			if (mp[i][j] == 0) {
				return 0;
			}
		}
	}return 1;
}

void PingJu()//设置平局弹窗
{
		HWND dow = GetHWnd();
		int window = MessageBox(NULL, "游戏结束!这盘是平局噢~是否重新开始游戏呢", "游戏结束", MB_OKCANCEL);
		if (window == IDOK) {//是否开始重新游戏
			initmap();//清除地图
			DoubleGame();
		}
		else if (window == IDCANCEL) {
			initmap();//清除地图
			//cleardevice();//清屏
			CreatMenu();//返回主菜单
		}
	
}

void CreatBoard()
{
	setbkcolor(RGB(190, 152, 122));//棋盘颜色
	cleardevice();//清屏
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 2);
	rectangle(30, 30, 520, 520);
	int space = 50;//设置棋盘左上角的位置
	setlinestyle(PS_SOLID, 1);
	for (int i = 0; i <16; i++) {//绘制棋盘
		line(space, space + i * 30, 500, space + i * 30);
	}
	for (int i = 0; i < 16; i++) {
		line( space + i * 30, space,space + i * 30,500);
	}
	setlinecolor(BLACK);
	setfillcolor(RGB(126,89,61));
	fillrectangle(540, 270, 650, 310);
	fillrectangle(540, 330, 650, 370);
	fillrectangle(540, 390, 650, 430);
	settextstyle(15, 0, "宋体");
	settextcolor(WHITE);
	rectangle(553, 97, 650, 138);
	rectangle(553,137 , 650, 178);
	outtextxy(560, 100, "P1 白棋");
	outtextxy(560, 120, "空格键下棋");
	outtextxy(560, 145, "P2 黑棋");
	outtextxy(560, 160, "Enter键下棋");
	settextstyle(20, 0, "黑体");//设置字体
	setbkmode(TRANSPARENT);//设置字体背景模式
	settextcolor(BLACK);//设置选项字体颜色
	outtextxy(548, 278, "按C键求和");
	outtextxy(548, 338, "按R键悔棋");
	outtextxy(548, 398, "按B键返回");
	
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 16; j++) {
			if (mp[i][j] == 1) {
				setfillcolor(WHITE);
				fillcircle(50+j*30, 50+i*30, 10);
			}
			if (mp[i][j] == 2) {
				setfillcolor(BLACK);
				fillcircle(50 + j * 30, 50 + i * 30, 10);
			}
		}
	}

}

void CreatMachineBoard()
{
	setbkcolor(RGB(190, 152, 122));//棋盘颜色
	cleardevice();//清屏
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 2);
	rectangle(30, 30, 520, 520);
	int space = 50;//设置棋盘左上角的位置
	setlinestyle(PS_SOLID, 1);
	for (int i = 0; i < 16; i++) {//绘制棋盘
		line(space, space + i * 30, 500, space + i * 30);
	}
	for (int i = 0; i < 16; i++) {
		line(space + i * 30, space, space + i * 30, 500);
	}
	setlinecolor(BLACK);
	setfillcolor(RGB(126, 89, 61));
	//fillrectangle(540, 270, 650, 310);
	fillrectangle(540, 330, 650, 370);
	fillrectangle(540, 390, 650, 430);
	settextstyle(15, 0, "宋体");
	settextcolor(WHITE);
	rectangle(553, 97, 650, 138);
	rectangle(553, 137, 650, 178);
	outtextxy(560, 100, "玩家:白棋");
	outtextxy(560, 120, "鼠标操作");
	outtextxy(560, 145, "电脑:黑棋");
	//(560, 160, "电脑");
	settextstyle(20, 0, "黑体");//设置字体
	setbkmode(TRANSPARENT);//设置字体背景模式
	settextcolor(BLACK);//设置选项字体颜色
	//outtextxy(548, 278, "认输");
	outtextxy(568, 340, "悔棋");
	outtextxy(568, 400, "返回");

	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 16; j++) {
			if (mp[i][j] == 1) {
				setfillcolor(WHITE);
				fillcircle(50 + j * 30, 50 + i * 30, 10);
			}
			if (mp[i][j] == 2) {
				setfillcolor(BLACK);
				fillcircle(50 + j * 30, 50 + i * 30, 10);
			}
		}
	}

}

void RegretChess()//悔棋操作,删除栈顶标记
{
	mp[ChessY.top()][ChessX.top()] = 0;
}

int  PlayWChess()//用键盘操作白棋下棋
{
	//int x = 50, y = 50;//棋子的起始位置	
	 flagW = 0;
			
	while (1) {
		CreatBoard();
		setlinestyle(PS_SOLID, 2);
		setlinecolor(GREEN);
		rectangle(nx - 10, ny - 10, nx + 10, ny + 10);
			char key = _getch();
			switch (key) {
			case 32:
				if (mp[(ny - 50) / 30][(nx - 50) / 30] == 1 || mp[(ny - 50) / 30][(nx - 50) / 30] == 2) {
					HWND dow = GetHWnd();
					int window = MessageBox(dow, "错误:该位置已有棋子!", "提示", MB_OKCANCEL);
				}
				else {
					Play_Bgm();
					//mciSendString("play xqBGM", 0, 0, 0);
					flagW = 1;
					mp[(ny - 50) / 30][(nx - 50) / 30] = 1;//标记为白棋
					Nowx = (nx - 50) / 30, Nowy = (ny - 50) / 30;
					ChessX.push((nx - 50) / 30), ChessY.push((ny - 50) / 30);
					break;
				}
 			//case 72:
			case 'w':
			case 'W':
				if (nx >= 50 && nx <= 500 && ny >= 80 && ny <= 500) { ny -= 30; }//往上移动
				break;
			//case 80:
			case 's':
			case 'S':
				if (nx >= 50 && nx <= 500 && ny >= 50 && ny <= 470) { ny += 30; }//往下移动
				break;
			//case 75:
			case 'a':
			case 'A':
				if (nx >= 80 && nx <= 500 && ny >= 50 && ny <= 500) {
					nx -= 30;
				}//往左移动
				break;
			//case 77:
			case 'd':
			case 'D':
				if (nx >= 50 && nx <= 470 && ny >= 50 && ny <= 500) {
					nx += 30;
				}//往右移动
				break;
			case 'c':
			case 'C':
				flagW = 2;
				return 2;//若求和则返回2
			case 'R':
			case 'r':
				if (RtimesW != 0) {//当白棋悔棋次数不为0时,控制悔棋次数
					RegretChess();
					RtimesW--;
					PlayBChess();
				}
				else {
					HWND tishi = GetHWnd();
					MessageBox(tishi, "悔棋次数已用光", "提示", MB_OKCANCEL);
				}break;
			case 'B':
			case 'b':
				return 1;
			}if (flagW == 1) break;
	}
	return 0;
}

void Play_Bgm() {
	mciSendString("play 下棋.wav", 0, 50, 0);
}

int PlayBChess()//用键盘操作黑棋下棋
{
	 flagB = 0;

	while (1) {
		CreatBoard();
		//setfillcolor(RED);
		//fillcircle(nx, ny, 10);
		setlinestyle(PS_SOLID, 2);
		setlinecolor(GREEN);
		rectangle(nx-10,ny-10 , nx+10, ny+10);

		char key = _getch();
		switch (key) {
		case 13:
			if (mp[(ny - 50) / 30][(nx - 50) / 30] == 1 || mp[(ny - 50) / 30][(nx - 50) / 30] == 2) {
				HWND dow = GetHWnd();
				int window = MessageBox(dow, "错误:该位置已有棋子!", "提示", MB_OKCANCEL);
			}
			else {
				Play_Bgm();				
				flagB = 1;
				mp[(ny - 50) / 30][(nx - 50) / 30] = 2;//标记为黑棋
				Nowx = (nx - 50) / 30, Nowy = (ny - 50) / 30;
				ChessX.push((nx - 50) / 30), ChessY.push((ny - 50) / 30);
				break;
			}
		case 72:
			if (nx >= 50 && nx <= 500 && ny >= 80 && ny <= 500) { ny -= 30; }//往上移动
			break;
		case 80:
			if (nx >= 50 && nx <= 500 && ny >= 50 && ny <= 470) { ny += 30; }//往下移动
			break;
		case 75:
			if (nx >= 80 && nx <= 500 && ny >= 50 && ny <= 500) {
				nx -= 30;
			}//往左移动
			break;
		case 77:
			if (nx >= 50 && nx <= 470 && ny >= 50 && ny <= 500) {
				nx += 30;
			}//往右移动
			break;
		case 'c':
		case 'C':
			
			flagB = 2;
			return 1;
		case 'R':
		case 'r':
			if (RtimesB!= 0) {//当白棋悔棋次数不为0时,控制悔棋次数
				RegretChess();
				RtimesB--;
				PlayWChess();
			}
			else {
				HWND tishi = GetHWnd();
				MessageBox(tishi, "悔棋次数已用光", "提示", MB_OKCANCEL);
			}
			break;
		case 'B':
		case 'b':
			return 1;

		}if (flagB == 1) break;
	}return 0;
}

int dfsW(int dx,int dy,int x, int y,int step)//运用dfs查找白棋连子数
{
	if (mp[y][x]!=1) return step;//若白棋赢则返回该方向连起来的棋子数
	
	if (mp[y][x] == 1) {
		//cout << x << " "<<y;
			int tx = x + dx;
	        int ty = y + dy;
			//cout << " " << "step =" << step << " ";
				dfsW(dx,dy,tx, ty,step+1);
	}
}

int dfsB(int dx, int dy, int x, int y, int step)//运用dfs查找黑棋连子数
{
	if (mp[y][x] != 2) return step;//若黑棋赢则返回该方向连起来的棋子数

	if (mp[y][x] == 2) {
		cout << x << " "<<y;
		int tx = x + dx;
		int ty = y + dy;
		cout << " " << "step =" << step << " ";
			dfsB(dx, dy, tx, ty, step + 1);
	}
}

int SearchW(int x, int y)//判断白棋输赢
{
	if (mp[y][x] == 1) {
		for(int i=0;i<4;i++){

					int tx = x + Next[i][0], ty = y + Next[i][1];
					if (tx >= 0 && tx < 16 && ty >= 0 && ty < 16 && mp[ty][tx] == 1) {
						if ((dfsW(Next[i][0], Next[i][1], x, y, 0) + dfsW(-1*Next[i][0], -1*Next[i][1], x, y, 0) - 1) >= 5) {
						return 1;
						}
					}
				}
	}return 0;
}

int SearchB(int x, int y)//判断黑棋输赢
{
	cout << "1";
	if (mp[y][x] == 2) {
		for (int i = 0; i < 4; i++) {

			int tx = x + Next[i][0], ty = y + Next[i][1];		
			cout << "1";

				if (tx >= 0 && tx < 16 && ty >= 0 && ty < 16 && mp[ty][tx] == 2) {
					if ((dfsB(Next[i][0], Next[i][1], x, y, 0) + dfsB(-1*Next[i][0], -1*Next[i][1], x, y, 0) - 1) >= 5) {
						return 1;
					}
			}
		}
	}return 0;
}

/*int bfs(int x, int y)
{
	queue<stone>Chess;
	stone 
}*/

void PlayerPlay()//人机模式玩家用鼠标下棋
{
	CreatMachineBoard();
	MOUSEMSG msg;
	while (1) {
		setfillcolor(WHITE);
		msg = GetMouseMsg();//接受鼠标信息
		if (msg.uMsg == WM_LBUTTONDOWN) {//如果鼠标状态为按下左键
			if (msg.x >= 35 && msg.x <= 515 && msg.y >= 35 && msg.y <= 515) {
				if (mp[(msg.y - 35) / 30][(msg.x - 35) / 30] == 0) {
					Play_Bgm();
					fillcircle(msg.x, msg.y, 10);
					ChessX.push((msg.x - 35) / 30), ChessY.push((msg.y - 35) / 30);
					mp[(msg.y - 35) / 30][(msg.x - 35) / 30] = 1;//玩家下白棋
					Playery = (msg.y - 35) / 30, Playerx = (msg.x - 35) / 30;
					break;
				}
				else {
					HWND dow = GetHWnd();
					int window = MessageBox(dow, "错误:该位置已有棋子!", "提示", MB_OKCANCEL);
					//break;
				}

			}
			else if (msg.x > 540 && msg.x < 650 && msg.y>330 && msg.y < 370) {//当鼠标选中悔棋边框
				if (Mtimes > 0) {//若剩余悔棋次数则悔棋
					mp[ChessY.top()][ChessX.top()] = 0;
					ChessY.pop(), ChessX.pop();//取出栈顶元素
					mp[ChessY.top()][ChessX.top()] = 0;
					Mtimes = Mtimes - 2;
					PlayerPlay();
					break;
				}
				else {
					HWND tishi = GetHWnd();
					MessageBox(tishi, "悔棋次数已用光", "提示", MB_OKCANCEL);
				}

			}
			else if (msg.x > 540 && msg.x < 650 && msg.y>390 && msg.y < 430) {
				initmap();//清除地图
				CreatMenu();//返回主菜单
				break;
			}
		}
	}
}

void DoubleGame()
{
	//mciSendString("open E:/Documents/temp/五子棋/五子棋/下棋.wav alias xqBGM", 0, 0, 0);

	nx = 50, ny = 50;//棋子的起始位置	
	while (1) {
		if (AllBoard() == 1) {//判断地图下满
			PingJu();
			break;
		} 
		if (PlayWChess() == 1) {//先下白棋,再下黑棋
			if (flagW == 0) {//标志为0时返回主菜单
				initmap();//清除地图
				//cleardevice();//清屏
				CreatMenu();//返回主菜单
				break;
			}
			else if (flagW == 2) {
				HWND dow = GetHWnd();
				int window = MessageBox(NULL, "求和成功~这盘是平局呢,是否重新开始游戏呢", "游戏结束", MB_OKCANCEL);
				if (window == IDOK) {//是否开始重新游戏
					initmap();//清除地图
					DoubleGame();
				}
				else if (window == IDCANCEL) {//返回主菜单
					initmap();//清除地图
					//cleardevice();//清屏
					CreatMenu();//返回主菜单
					break;
				}
			}
		}if (AllBoard() == 1) {//判断地图下满
			PingJu(); 
			break;
		}
			if (SearchW(Nowx, Nowy) == 1) {	
				mciSendString("play ./胜利呼喊声.wav", 0, 0, 0);
				HWND dow = GetHWnd();
				int window = MessageBox(NULL, "恭喜,玩家1获胜,亲,是否继续游戏呢", "游戏结束", MB_OKCANCEL);
				if (window == IDOK) {//是否开始重新游戏
					initmap();//清除地图
					//CreatBoard();
					DoubleGame();
				}
				else if (window == IDCANCEL) {
					initmap();//清除地图
					//cleardevice();//清屏
					CreatMenu();//返回主菜单
				}
				break;
			}
			if (PlayBChess() == 1) {//先下白棋,再下黑棋
				if (flagB == 0) {//如果标志为0则返回主菜单 
					initmap();//清除地图
					//cleardevice();//清屏
					CreatMenu();//返回主菜单
					break;
				}
				else if (flagB == 2) {//如果标志为2
					HWND dow = GetHWnd();
					int window = MessageBox(NULL, "求和成功~这盘是平局呢,是否重新开始游戏呢", "游戏结束", MB_OKCANCEL);
					if (window == IDOK) {//是否开始重新游戏
						initmap();//清除地图
						//CreatBoard();
						DoubleGame();
					}
					else if (window == IDCANCEL) {
						initmap();//清除地图
						//cleardevice();//清屏
						CreatMenu();//返回主菜单					
					}
					break;
				}
			}
			if (SearchB(Nowx, Nowy) == 1) {
				mciSendString("play ./胜利呼喊声.wav", 0, 0, 0);
				HWND dow = GetHWnd();
				int window = MessageBox(dow, "恭喜,玩家2获胜,亲,是否继续游戏呢", "游戏结束", MB_OKCANCEL);
				if (window == IDOK) {//是否开始重新游戏
					initmap();//清除地图
					//CreatBoard();
					DoubleGame();
				}
				else if (window == IDCANCEL) {
					initmap();//清除地图
					//cleardevice();//清屏
					CreatMenu();//返回主菜单
				}
				break;
			}
	}
}

int CountPScore(int empty, int lianzi)//计算分数,前者为空白位置数,后者为连子个数
{
	int score = 0;//连一时分数为0
	if (empty == 2 && lianzi == 3) score = 800;//活四分数为1000
	else if (empty == 2 && lianzi == 2) score = 160;//活三为100
	else if (empty == 1 && lianzi == 3) score = 240;//冲四为100
	else if (empty == 1 && lianzi == 2) score = 120;//死三为50
	else if (empty == 2 && lianzi == 1) score = 40;//连二为20
	else if (lianzi == 4) score = 20000;//活五为20000
	//cout << empty<<endl<<lianzi<<endl;
	return score;
} 

int CountAScore(int empty, int lianzi)//计算分数,前者为空白位置数,后者为连子个数
{//因为电脑先手,于是我们可以把电脑的分数设的比玩家高一点
	int score = 0;//连一时分数为0
	if (empty == 2 && lianzi == 3) score = 1200;//活四分数为1000
	else if (empty == 2 && lianzi == 2) score = 200;//活三为100
	else if (empty == 1 && lianzi == 3) score = 260;//冲四为100
	else if (empty == 1 && lianzi == 2) score = 130;//死三为50
	else if (empty == 2 && lianzi == 1) score = 45;//连二为20
	else if (lianzi == 4) score = 30000;//活五为20000
	//cout << empty << endl << lianzi << endl;
	return score;
}

int PlayerScore(int y, int x)//每一次玩家下棋后该位置玩家下棋的分数
{
	int sum = 0;//每个位置的总分数
	//if (EndPlay(y, x)) return 20000;//判断一方取得胜利则返回20000
	int empty = 0;
	int Plianzi = 0;//前一个表示空白位置个数,后一个表示玩家棋两边连起来的个数
	for (int i = 0; i < 4; i++) {//四个方向
		empty = 0, Plianzi = 0;
		for (int j = 1; j < 5; j++) {//往一个方向前进,计算一个方向连子个数
			int nx = x + j * Next[i][0], ny = y + j * Next[i][1];
			if (nx < 0 || nx>16 || ny < 0 || ny>16) {
				break;
			}
			if (mp[ny][nx] == 0) {
				empty++;
				break;
			}
			if (mp[ny][nx] == 2) {
				break;
			}
			else if (mp[ny][nx] == 1) {
				Plianzi++;
			}
		}
		
		for (int j = 1; j < 5; j++) {//往一个方向前进,计算一个方向连子个数
			int nx = x + (-1) * j * Next[i][0], ny = y + (-1) * j * Next[i][1];
			if (nx < 0 || nx >= 16 || ny < 0 || ny >= 16) {//判断出界
				break;
			}
			if (mp[ny][nx] == 0) {
				//若此时下一个位置为空白位置时
				empty++;//空白位置数加一
				break;
			}
			else if (mp[ny][nx] == 2) {
				break;
			}
			else if (mp[ny][nx] == 1) {
				//若此时下一个位置为白棋(即玩家棋)时
				Plianzi++;//玩家棋连起来的个数
			}
		}sum += CountPScore(empty, Plianzi);//四个方向分数相加
	}return sum;
}

int AIScore(int y, int x)//每一次玩家下棋后该位置电脑下棋的分数
{
	int sum = 0;
	int empty = 0; int Alianzi = 0;//前一个表示空白位置个数,后一个表示玩家棋连起来的个数
	for (int i = 0; i < 4; i++) {//四个方向
		empty = 0, Alianzi = 0;
		for (int j = 1; j < 5; j++) {//往一个方向前进,计算一个方向连子个数
			int nx = x + j * Next[i][0], ny = y + j * Next[i][1];
			if (nx < 0 || nx >= 16 || ny < 0 || ny >= 16) {//判断出界
				break;
			}
			if (mp[ny][nx] == 0) {
				//若此时下一个位置为空白位置时
				empty++;//空白位置数加一
				break;
			}
			else if (mp[ny][nx] == 1) {
				break;
			}
			else if (mp[ny][nx] == 2) {
				//若此时下一个位置为黑棋(即电脑棋)时
				Alianzi++;//玩家棋连起来的个数
			}
		}
		for (int j = 1; j < 5; j++) {//往一个方向前进,计算一个方向连子个数
			int nx = x + (-1) * j * Next[i][0], ny = y + (-1) * j * Next[i][1];
			if (nx < 0 || nx >= 16 || ny < 0 || ny >= 16) {//判断出界
				break;
			}
			if (mp[ny][nx] == 0) {
				//若此时下一个位置为空白位置时
				empty++;//空白位置数加一
				break;
			}
			else if (mp[ny][nx] == 1) {
				break;
			}
			else if (mp[ny][nx] == 2) {
				//判断是否出界且若此时下一个位置为黑棋(即电脑棋)时
				Alianzi++;//玩家棋连起来的个数
			}
		}sum += CountAScore(empty, Alianzi);//将四个方向的分数相加
	}return sum;
}

int AIplay()//电脑下棋
{
	CreatMachineBoard();
	setfillcolor(BLACK);

	if (mp[7][7] == 0) {
		Play_Bgm();
		fillcircle(7, 7, 10);
		ChessX.push(7), ChessY.push(7);
		mp[7][7] = 2;//电脑先下棋,第一个下棋盘中间,且是黑棋
		return 0;
	}
	int ScoreMax = 0;
	int mpx=0, mpy=0;
	int  AIscore;
	for (int i = 0; i < 16; i++) {//y
		for (int j = 0; j < 16; j++) {//x
			if (mp[i][j]!= 0) continue;//此位置已被占
			 AIscore = PlayerScore(i,j)+ AIScore(i, j);//计算该位置分数,取两者之和,即可攻可守为最好方法
			 //cout << PlayerScore(i, j) << endl << AIScore(i, j);
			if (AIscore == 0) {//分数为0直接跳过
				continue;
			}			
			else if (AIscore >= 30000) {//当分数大于等于30000,即可以连成五棋时,电脑胜利,结束游戏
				fillcircle((j*30)+35+15, (i*30)+35+15 , 10);
				ChessX.push(j), ChessY.push(i);
				mp[i][j] = 2;
				return 2;//电脑赢
			}
			 else if (AIscore >ScoreMax) {
				swap(AIscore, ScoreMax);//若当前位置分数比ScoreMax高,则交换数值
				mpx = j; mpy = i;//记录下全位置分数最高的位置
			}
		}
	}
	Play_Bgm();
	fillcircle((mpx * 30) + 35, (mpy * 30) + 35, 10);//在全位置分数最高的地方下棋
	ChessX.push(mpx), ChessY.push(mpy);
	mp[mpy][mpx] = 2;
	return 0;
}

void MachineGame()
{
	int step=0;//记录赢的步数
	while (1) {
		if (AllBoard() == 1) {//判断地图下满
			PingJu();//平局窗口
			break;
		}
		//AIplay();
		if (AIplay() == 2) {//电脑赢局
			mciSendString("play ./游戏失败.mp3", 0, 0, 0);
			HWND dow = GetHWnd();
			int window = MessageBox(NULL, "游戏结束,你失败了,是否重新开始游戏", "游戏结束", MB_OKCANCEL);
			if (window == IDOK) {//是否开始重新游戏
				initmap();//清除地图
				MachineGame();
			}
			else if (window == IDCANCEL) {
				initmap();//清除地图
				CreatMenu();//返回主菜单
			}
			break;
		}if (AllBoard() == 1) {//判断地图下满
			PingJu();
			break;
		}
		PlayerPlay();
		step++;
		if (SearchW(Playerx,Playery) == 1) {//玩家胜利
			mciSendString("play ./胜利呼喊声.wav", 0, 0, 0);
			FILE* test = fopen("排行榜.txt", "a");
			fprintf(test, "%d ", step);//将玩家胜利的步数存入排行榜文件
			fclose(test);
				HWND dow = GetHWnd();
			int window = MessageBox(NULL, "恭喜!你赢得本局游戏,是否继续游戏呢", "游戏结束", MB_OKCANCEL);
			if (window == IDOK) {//是否开始重新游戏
				initmap();//清除地图
				MachineGame();
			}
			else if (window == IDCANCEL) {
				initmap();//清除地图
				CreatMenu();//返回主菜单
			}
			break;
		}
	}
}

void RankList()
{
	IMAGE img;
	loadimage(&img, "E:/Documents/temp/五子棋/五子棋/排行榜背景.jpg", 670, 550);
	putimage(0, 0, &img);//插入图片
	settextstyle(50, 0, "黑体");//设置字体
	setbkmode(TRANSPARENT);//设置字体背景模式
	settextcolor(RGB(88,88,88));//设置字体颜色
	outtextxy(200,20,  "排");
	outtextxy( 300,20, "行");
	outtextxy( 400,20, "榜");
	settextcolor(RED);//设置字体颜色
	settextstyle(30, 0, "宋体");//设置字体
	outtextxy(120, 80, "第一名:");
	outtextxy(120, 120, "第二名:");
	outtextxy(120, 160, "第三名:");
	settextcolor(BLACK);//设置字体颜色
	settextstyle(20, 0, "宋体");//设置字体
	outtextxy(120, 200, "第四名:");
	outtextxy(120, 240, "第五名:");
	outtextxy(120, 280, "第六名:");
	outtextxy(120, 320, "第七名:");
	outtextxy(120, 360, "第八名:");
	outtextxy(120, 400, "第九名:");
	outtextxy(120, 440, "第十名:");

	int sstep[100] = { 0 };
	FILE* test = fopen("排行榜.txt", "r");//从文件中读取数据
	int i=0;
		while (fscanf(test, "%d", &sstep[i]) != EOF) {
			i++;
		}
	sort(sstep,sstep+i);//排序
	int textx = 400, texty = 80;
	for (int j = 0; j < i&&j<10; j++) {//从文件中读取数据生成排行榜
		char str;
		itoa(sstep[j], &str, 10);
		settextstyle(25, 0, "华文琥珀");//设置字体
		outtextxy(textx, texty,&str);
		texty += 40;
	}fclose(test);
		setfillcolor(RGB(88, 88, 88));
		fillrectangle(520, 500, 600, 530);
		settextstyle(25, 0, "楷体");//设置字体
		setbkmode(TRANSPARENT);//设置字体背景模式
		settextcolor(BLACK);//设置字体颜色
		outtextxy(530, 503, "返回");
	MOUSEMSG msg;
	while (1) {
		msg = GetMouseMsg();//接受鼠标信息
		if (msg.uMsg == WM_LBUTTONDOWN) {//如果鼠标状态为按下左键
			if (msg.x > 520 && msg.x < 600 && msg.y>500 && msg.y < 530) {//返回主菜单
				initmap();
				CreatMenu();
			}
		}
	}
}

void CreatMenu()//建立主菜单
{
	//initgraph(670, 550);
	IMAGE img;
	loadimage(&img, "E:/Documents/temp/五子棋/五子棋/主菜单背景.jpg", 670, 550); 
		putimage(0, 0, &img);//插入图片
		mciSendString("open E:/Documents/temp/五子棋/五子棋/背景音乐.mp3 alias bkBGM", 0, 0, 0);
		mciSendString("play bkBGM repeat", 0, 0, 0);

		setlinestyle(PS_SOLID, 1);//设置主菜单选项边框为实线,宽度为1像素
		setfillcolor(RGB(187,128,96));//设置填充颜色
		setlinecolor(WHITE);//设置线条颜色
		int Left = 80, Top = 180, Right = 300, Bottom = 240;
		for (int i = 1; i <= 4; i++) {//设置四个主菜单选项边框
			fillrectangle(Left, Top, Right, Bottom);
			Top += 90, Bottom += 90;
		}
		//setfillcolor(RGB(88, 88, 88));//设置填充颜色
		//fillrectangle(50, 50, 120, 90);		
		//settextstyle(30,0,"楷体");//设置字体
		setbkmode(TRANSPARENT);//设置字体背景模式
		
		settextstyle(50, 0, "楷体");//设置字体
		settextcolor(RGB(105, 55, 29));//设置字体颜色
		outtextxy(85, 185, "双人模式");
		outtextxy(85, 275, "人机模式");
		outtextxy(110, 365, "排行榜");
		outtextxy(85, 455, "退出游戏");


				/*fillrectangle(80, 180, 300, 240);
		fillrectangle(80,270,300,330);
		fillrectangle(80, 360, 300, 420);
		fillrectangle(80,450,300,510);*/
		MOUSEMSG msg;
		while (1) {
			/*		fillrectangle(50, 50, 120, 90);		
*/
			msg = GetMouseMsg();//接受鼠标信息
			if (msg.uMsg == WM_LBUTTONDOWN) {//如果鼠标状态为按下左键
				if (msg.x > 80 && msg.x < 300 && msg.y>180 && msg.y < 240) {
					mciSendString("play ./开始音效.wav", 0, 0, 0);
					DoubleGame();//开始双人游戏
					break;
				}
				if (msg.x > 80 && msg.x < 300 && msg.y>270 && msg.y < 330) {
					mciSendString("play ./开始音效.wav", 0, 0, 0);
					MachineGame();//开始人机模式
					break;
				}
				if (msg.x > 80 && msg.x < 300 && msg.y>360 && msg.y < 420) {
					mciSendString("play ./开始音效.wav", 0, 0, 0);
					RankList();//排行榜
					break;
				}
				if (msg.x > 80 && msg.x < 300 && msg.y>450 && msg.y < 510) {
					closegraph();//退出游戏
					break;
				}
			}
		}system("pause");
}

int main()
{
	initgraph(670, 550,SHOWCONSOLE);
	 CreatMenu();
	 closegraph();
	return 0;
}

 

 

 

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值