c语言黑白棋ai游戏源码

2021-01-04 10:34:05 浏览数 (1)

代码语言:javascript复制
#include <graphics.h>	// EasyX_2011惊蛰版
#include <strstream>
#include <ctime>
#pragma comment(lib, "Winmm.lib")
#define T(c) ((c == 'B') ? 'W' : 'B')
using namespace std;

// 来自公众号:c语言与cpp编程

/*******************************定义全局变量*****************************/
const int difficult = 6;	// 难度
const int move[8][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1},
						{-1, -1}, {1, -1}, {1, 1}, {-1, 1}};
							// 八个方向扩展
char map[8][8];				// 棋盘
IMAGE img[5];				// 保存图片
int black, white;			// 双方的棋子数
int X, Y;					// 白棋的下子点

/**********************************函数声明*****************************/
void load(void);				// 加载素材
void print(void);				// 画棋盘
void draw(int, int, char);		// 下当前子
int judge(int, int, char);		// 判断当前是否可以落下
bool baidu(char);				// 判断是否有棋可吃
bool quit(char);				// 判断是否有棋存活
bool ask(void);					// 弹出对话框
int D(char, int);				// 动态规划
void play(void);				// 游戏过程

/**********************************定义函数*****************************/
void load(void)		// 加载素材
{
	// 加载图片
	loadimage(&img[0], "图片\空位.bmp");
	loadimage(&img[1], "图片\黑子.bmp");
	loadimage(&img[2], "图片\白子.bmp");
	loadimage(&img[3], "图片\黑子1.bmp");
	loadimage(&img[4], "图片\白子1.bmp");

	// 加载音乐
	mciSendString("open 音乐\背景音乐.wma", NULL, 0, NULL);
	mciSendString("open 音乐\和局.wma", NULL, 0, NULL);
	mciSendString("open 音乐\胜利.wma", NULL, 0, NULL);
	mciSendString("open 音乐\失败.wma", NULL, 0, NULL);
	mciSendString("open 音乐\下子.wma", NULL, 0, NULL);

	// 初始化棋盘
	initgraph(340, 340);
	IMAGE qipan;
	loadimage(&qipan, "图片\棋盘.bmp");
	putimage(0, 0, &qipan);
	setorigin(26, 26);
	SetWindowText(GetHWnd(), "黑白棋AI版");
}

void print(void)	// 画棋盘
{
	int x, y;
	black = white = 0;
	for(x = 0; x < 8; x  )
		for(y = 0; y < 8; y  )
			switch(map[x][y])
			{
				case 0:
						putimage(37 * y, 37 * x, &img[0]);
					break;
				case 'B':
						putimage(37 * y, 37 * x, &img[1]);
					black  ;
					break;
				case 'W':
						putimage(37 * y, 37 * x, &img[2]);
					white  ;
					break;
			}
}

void draw(int x, int y, char a)	// 下当前子
{
	char b = T(a);									// 敌方子
	int i, x1, y1, x2, y2;
	bool sign;			
	for (i = 0; i < 8; i  )
	{
		sign = false;
		x1 = x   move[i][0];
		y1 = y   move[i][1];
		while (0 <= x1 && x1 < 8 && 0 <= y1 && y1 < 8 && map[x1][y1])
		{
			if(map[x1][y1] == b)
				sign = true;
			else
			{
				if(sign)
				{
					x1 -= move[i][0];
					y1 -= move[i][1];
					x2 = x   move[i][0];
					y2 = y   move[i][1];
					while (((x <= x2 && x2 <= x1) || (x1 <= x2 && x2 <= x)) && ((y <= y2 && y2 <= y1) || (y1 <= y2 && y2 <= y)))
					{
						map[x2][y2] = a;
						x2  = move[i][0];
						y2  = move[i][1];
					}
				}
				break;
			}
			x1  = move[i][0];
			y1  = move[i][1];
		}
	}
	map[x][y] = a;
}

int judge(int x, int y, char a)	// 判断当前是否可以落下,同draw函数
{
	if(map[x][y])						// 如果当前不是空的返回0值
		return 0;
	char b = T(a);
	int i, x1, y1;
	int n = 0, sign;
	for (i = 0; i < 8; i  )
	{
		sign = 0;
		x1 = x   move[i][0];
		y1 = y   move[i][1];
		while (0 <= x1 && x1 < 8 && 0 <= y1 && y1 < 8 && map[x1][y1])
		{
			if(map[x1][y1] == b)
				sign  ;
			else
			{
				n  = sign;
				break;
			}
			x1  = move[i][0];
			y1  = move[i][1];
		}
	}
	return n;		// 返回可吃棋数
}

bool baidu(char c)	// 判断是否有棋可吃
{
	int x, y;
	for(x = 0; x < 8; x  )
		for(y = 0; y < 8; y  )
			if(judge(x, y, c))
				return true;
	return false;
}

bool quit(char c)	// 判断是否有棋存活
{
	int x, y;
	bool b = false, w = false;
	for(x = 0; x < 8; x  )
		for(y = 0; y < 8; y  )
		{
			if(map[x][y] == c)
				return false;
		}
	return true;
}

bool ask(void)	// 弹出对话框
{
	HWND wnd = GetHWnd();
	int key;
	char str[50];
	ostrstream strout(str, 50);
	strout <<"黑:" <<black <<"  白:" <<white <<endl;
	if (black == white)
		strout <<"世界和平";
	else if(black > white)
		strout <<"恭喜你赢了!";
	else
		strout <<"小样,还想赢我。";
	strout <<"n再来一局吗?" <<ends;
	if(black == white)
		key = MessageBox(wnd, str, "和局", MB_YESNO | MB_ICONQUESTION);
	else if(black > white)
		key = MessageBox(wnd, str, "黑胜", MB_YESNO | MB_ICONQUESTION);
	else
		key = MessageBox(wnd, str, "白胜", MB_YESNO | MB_ICONQUESTION);
	if(key == IDYES)
		return true;
	else
		return false;
}

int D(char c, int step)
{
	// 判断是否结束递归
	if (step > difficult)	// 约束步数之内
		return 0;
	if (!baidu(c))
	{
		if (baidu(T(c)))
			return -D(T(c), step);
		else
			return 0;
	}

	int i, j, max = 0, temp, x, y;
	bool ans = false;

	// 建立临时数组
	char **t = new char *[8];
	for (i = 0; i < 8; i  )
		t[i] = new char [8];
	for (i = 0; i < 8; i  )
		for (j = 0; j < 8; j  )
			t[i][j] = map[i][j];

	// 搜索解法
	for (i = 0; i < 8; i  )
		for (j = 0; j < 8; j  )
			if (temp = judge(i, j, c))
			{
				draw(i, j, c);
				temp -= D(T(c), step   1);
				if (temp > max || !ans)
				{
					max = temp;
					x = i;
					y = j;
					ans = true;
				}
				for (int k = 0; k < 8; k  )
					for (int l = 0; l < 8; l  )
						map[k][l] = t[k][l];
			}

	// 撤销空间
	for (i = 0; i < 8; i  )
		delete [] t[i];
	delete [] t;

	// 如果是第一步则标识白棋下子点
	if (step == 1)
	{
		X = x;
		Y = y;
	}

	return max;	// 返会最优解
}

void play(void)			// 游戏过程
{
	MOUSEMSG m;
	int x, y;

	// 初始化棋子
	for(x = 0; x < 8; x  )
		for(y = 0; y < 8; y  )
			map[x][y] = 0;
	map[3][4] = map[4][3] = 'B';
	map[3][3] = map[4][4] = 'W';

	// 开始游戏
	print();
	mciSendString("play 音乐\背景音乐.wma from 0 repeat", NULL, 0, NULL);
	do
	{
		if (baidu('B'))										// 如果玩家有下子位置							
		{
			A:
			while(true)
			{
				m = GetMouseMsg();							// 获取鼠标消息
				if(m.uMsg == WM_LBUTTONDOWN && m.x - 26 < 37 * 8 && m.y - 26 < 37 * 8)
															// 如果左键点击
					break;
			}
			x = (m.y - 26) / 37;
			y = (m.x - 26) / 37;
			if(judge(x, y, 'B'))							// 如果当前位置有效
			{
				draw(x, y, 'B');							// 下子
				mciSendString("play 音乐\下子.wma from 0", NULL, 0, NULL);
				print();
				putimage(37 * y, 37 * x, &img[3]);			// 标识下子点
			}
			else
				goto A;
			if (quit('W'))									// 计算机是否失败
				break;
		}
		if (baidu('W'))										// 如果计算机有下子位置
		{
			clock_t start;
			start = clock();
			D('W', 1);										// 搜索解法
			while (clock() - start < CLOCKS_PER_SEC);
			draw(X, Y, 'W');
			print();
			mciSendString("play 音乐\下子.wma from 0", NULL, 0, NULL);
			putimage(37 * Y, 37 * X, &img[4]);	// 标识下子点
			if (quit('B'))									// 玩家是否失败
				break;
		}
	}while (baidu('B') || baidu ('W'));

	// 播放庆祝音乐
	mciSendString("stop 音乐\背景音乐.wma", NULL, 0, NULL);
	if (black > white)
		mciSendString("play 音乐\胜利.wma from 0", NULL, 0, NULL);
	else if (black < white)
		mciSendString("play 音乐\失败.wma from 0", NULL, 0, NULL);
	else
		mciSendString("play 音乐\和局.wma from 0", NULL, 0, NULL);
}

// 主函数
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	load();
	do
	{
		play();
	} while(ask());

	// 关闭音乐
	mciSendString("close 音乐\背景音乐.wma", NULL, 0, NULL);
	mciSendString("close 音乐\和局.wma", NULL, 0, NULL);
	mciSendString("close 音乐\胜利.wma", NULL, 0, NULL);
	mciSendString("close 音乐\失败.wma", NULL, 0, NULL);
	mciSendString("close 音乐\下子.wma", NULL, 0, NULL);
	closegraph();
	return 0;
}

/***********************************THE END**********

0 人点赞