十分钟开发出神经网络五子棋

本文讲述了使用确定性神经网络SDK开发神经网络五子棋的过程,通过控制台项目、MFC对话框项目分别展示了详细的操作和代码,并附带了一个可用于自主创业的实用案例。另外,此处所述的五子棋可以轻易地扩展成其它的连子棋应用。

1.控制台版本的神经网络五子棋

(1)创建项目

运行Visual Studio 2015(其它版本的VS也可以使用),选择菜单“文件-->新建-->项目”,在对话框的左侧选择“已安装-->模板-->Visual C++-->Win32”,在右侧选择“Win32控制台应用程序”,并选定项目保存的位置和项目名称(此处项目名为test,保存在桌面),如下图所示:

十分钟开发出神经网络五子棋_第1张图片

 点击“确定”按钮,在弹出的对话框的左侧选择“应用程序设置”,右侧选择“空项目”,并取消“安全开发生命周期(SDL)检查”的选择,详细如下图所示:

十分钟开发出神经网络五子棋_第2张图片

 点击“完成”按钮,至此完成了控制台项目的创建。

 (2)新建程序文件

在解决方案资源管理器中右击test项目,在右键菜单中选择“添加-->新建项”,在弹出的对话框左侧选择“已安装-->Visual C++-->代码”,在右侧选择“C++文件”,在下方输入源代码文件的名称(本例为test.cpp),如下图所示:

十分钟开发出神经网络五子棋_第3张图片

 点击“添加”按钮,然后即可开始编写代码。

(3)导入SDK

打开test.cpp所在的目录,将SDK文件(AIWZQDll.dll、AIWZQDll.lib、Inter.h)拷贝到该目录,如下图:

十分钟开发出神经网络五子棋_第4张图片

然后,在解决方案资源管理器中右击test项目,在右键菜单中选择“添加-->现有项” ,在弹出的对话框中选中Inter.h并点击“添加”按钮即可。

(4)编写代码

打开test.cpp文件,输入如下两句代码来引入SDK:

#include "Inter.h"
#pragma comment(lib, "AIWZQDll.lib")

然后添加main()函数,在该函数开头调用SDK的Login()函数如下:

void main()
{
	if (!Login("user", "password"))
	{
		printf("登录失败\n");
		getchar();
		return;
	}
}

其中:user和password是调用确定性神经网络所使用的用户名和密码,可以在官网www.gnxxkj.com下载客户端软件进行用户注册,并将注册的用户名和密码填至此处。

然后调用InitFromModelFile()函数加载神经网络模型:

	if (!InitFromModelFile("model.mod"))
	{
		printf("初始化失败\n");
		getchar();
		return;
	}

如果没有神经网络模型,也可以使用“棋盘大小”、“几连子获胜”这样的参数来调用InitWithoutModel()函数:

    if (!InitWithoutModelFile(15, 15, 5))
	{
		printf("初始化失败\n");
		getchar();
		return;
	}

此处表示从空模型开始,创建15x15大小棋盘上的五子棋游戏,若要创建六子棋则将函数的第三个参数从5改为6即可。注:若使用已有模型,在模型中已经包含了棋盘大小和几连子获胜这样的信息。

接下来调用StartNewGame()函数来开始一局游戏:

	if (!StartNewGame())
	{
		printf("游戏开始失败\n");
		getchar();
		return;
	}

该函数将初始化内存和游戏基础数据。之后,就可以循环调用SetPieceByAI()函数来落子了,每一次落子后都调用IsGameOver()函数来判断游戏是否结束:

	while (!IsGameOver())
	{
		if (!SetPieceByAI())
		{
			printf("积分不足或网络问题,请确保网络畅通且积分充足(若是积分不足,充值后可继续本次对局\n");
			printf("当前积分为:%d\n", GetPoint());
			break;
		}
		Show();
		getchar();	//等待用户按键盘落下一子
	}

其中:SetPieceByAI()将调用神经网络的预测功能预测下一次落子位置,并在相应位置落子,然后通过Show()函数显示出来,通过getchar()函数来实现用户按一次键盘就落一子的操作。此处的Show()函数简单定义如下:

void Show()
{
	int nBoardWidth = 0;	//棋盘宽度
	int nBoardHeight = 0;	//棋盘高度
	TBOARD* pData = GetBoardData(&nBoardWidth, &nBoardHeight);
	if (pData == NULL || nBoardWidth < 1 || nBoardHeight < 1)
	{
		printf("无效数据\n");
		return;
	}

	printf("=============================================================================\n");
	for (int h = 0; h < nBoardHeight; h++)
	{
		for (int w = 0; w < nBoardWidth; w++)
		{
			switch (pData[h*nBoardWidth + w])
			{
			case -1:	//黑子
				printf("X ");
				break;
			case 1:		//白子
				printf("O ");
				break;
			case 0:		//空白,该位置尚未落子
				printf("- ");
				break;
			default:	//无效数据
				break;
			}
		}
		printf("\n");
	}
	printf("===============================================================================\n");
}

该函数调用SDK函数GetBoardData()来获取当前棋局数据,并在控制台上显示出来。该Show()函数将在对话框案例中进行重写更换。

一旦IsGameOver()函数返回真,则游戏结束,此时可以调用GetWinner()函数来检测获胜者:

	switch (GetWinner())
	{
	case -1:
		printf("黑棋获胜\n");
		break;
	case 1:
		printf("白棋获胜\n");
		break;
	case 0:
		printf("平局\n");
		break;
	}
	getchar();

至此,游戏主体已经结束。另外,也可以在游戏结束时调用SaveModel()函数来保存游戏中的神经网络模型,该模型在每次游戏结束后会重新训练和更新,所以会随着游戏次数的增多而不断进化;还可以调用SaveSteps()函数来保存本次对弈的数据,即本局游戏每步落子的位置、谁落的子(黑/白):

	SaveModel("model.mod");
	SaveSteps("data.txt");

(5)测试

运行项目,在控制台界面中不断按键盘来显示下一次落子位置,直至结束:

十分钟开发出神经网络五子棋_第5张图片

 (6)完整代码如下:


#include "stdio.h"

#include "Inter.h"
#pragma comment(lib, "AIWZQDll.lib")

void Show()
{
	int nBoardWidth = 0;	//棋盘宽度
	int nBoardHeight = 0;	//棋盘高度
	TBOARD* pData = GetBoardData(&nBoardWidth, &nBoardHeight);
	if (pData == NULL || nBoardWidth < 1 || nBoardHeight < 1)
	{
		printf("无效数据\n");
		return;
	}

	printf("=============================================================================\n");
	for (int h = 0; h < nBoardHeight; h++)
	{
		for (int w = 0; w < nBoardWidth; w++)
		{
			switch (pData[h*nBoardWidth + w])
			{
			case -1:	//黑子
				printf("X ");
				break;
			case 1:		//白子
				printf("O ");
				break;
			case 0:		//空白,该位置尚未落子
				printf("- ");
				break;
			default:	//无效数据
				break;
			}
		}
		printf("\n");
	}
	printf("===============================================================================\n");
}

void main()
{
	if (!Login("user", "password"))
	{
		printf("登录失败\n");
		getchar();
		return;
	}

	if (!InitWithoutModelFile(15, 15, 5))
	{
		printf("初始化失败\n");
		getchar();
		return;
	}

	//使用模型文件初始化
	//if (!InitFromModelFile("model.mod"))
	//{
	//	printf("初始化失败\n");
	//	getchar();
	//	return;
	//}

	if (!StartNewGame())
	{
		printf("游戏开始失败\n");
		getchar();
		return;
	}

	while (!IsGameOver())
	{
		if (!SetPieceByAI())
		{
			printf("积分不足或网络问题,请确保网络畅通且积分充足(若是积分不足,充值后可继续本次对局\n");
			printf("当前积分为:%d\n", GetPoint());
			break;
		}
		Show();
		getchar();	//等待用户按键盘落下一子
	}

	switch (GetWinner())
	{
	case -1:
		printf("黑棋获胜\n");
		break;
	case 1:
		printf("白棋获胜\n");
		break;
	case 0:
		printf("平局\n");
		break;
	}
	getchar();

	SaveModel("model.mod");
	SaveSteps("data.txt");
}

(7)完整的Inter.h文件如下:


typedef signed char TBOARD;

//以下函数在程序运行开始的时候调用,仅调用一次
extern "C" __declspec(dllexport) bool Login(char* strLoginName, char* strPassword);		//登录

extern "C" __declspec(dllexport) bool InitFromModelFile(char* strModelFileName);	//使用模型文件初始化
extern "C" __declspec(dllexport) bool InitWithoutModelFile(int nBoardWidth, int nBoardHeight, int nWinLen);		//无模型文件时初始化

//以下函数在每局游戏开始的时候调用,每局游戏调用一次
extern "C" __declspec(dllexport) bool StartNewGame();			//开始游戏,并重置相关数据

//以下函数在每步落子的时候调用,每步落子调用一次
extern "C" __declspec(dllexport) bool SetPieceWithCoord(int nX, int nY);	//根据坐标落子
//extern "C" __declspec(dllexport) bool SetPieceWithGUI(CStatic* pCtrlBoard, int nCursorXInCtrl, int nCursorYInCtrl);		//根据界面组件及屏幕鼠标位置落子

extern "C" __declspec(dllexport) bool SetPieceByAI(void);					//AI落子,该函数返回失败表示所登录的用户积分不足
//extern "C" __declspec(dllexport) bool SetPieceByAIAndShow(CStatic* pCtrlBoard);		//AI落子并在界面上显示

extern "C" __declspec(dllexport) bool IsGameOver();		//游戏是否已经结束
extern "C" __declspec(dllexport) int GetWinner();		//获胜者

//extern "C" __declspec(dllexport) bool DrawBoard(CStatic* pCtrlBoard);		//绘制棋盘
//extern "C" __declspec(dllexport) bool DrawPieces(CStatic* pCtrlBoard);		//绘制所有棋子

//以下函数在需要的时候调用,非必须调用
extern "C" __declspec(dllexport) TBOARD* GetBoardData(int* pnBoardWidth, int* pnBoardHeight);	//获得当前棋局数组的内存区首地址(及矩阵的宽和高,如果需要的话)
extern "C" __declspec(dllexport) int GetPoint();

extern "C" __declspec(dllexport) bool SaveSteps(char* strDataFileName);		//保存棋局数据
extern "C" __declspec(dllexport) bool SaveModel(char* strModelFileName);	//保存模型数据

//以下函数用于“五子棋水平等级评估”
extern "C" __declspec(dllexport) bool SetLayers4Pred(int nLayers);		//设置用于预测的层数,与之同时,将禁止神经网络的学习进化,仅使用指定的模型进行预测,可保证公平性

该文件在控制台项目下使用和编译时需要注释掉出错的几行(出错的行是供GUI项目使用的,有GUI下的CStatic类型)。

2.MFC对话框版本的神经网络五子棋

原本打算将几个版本的案例一起写的,但是写完控制台版本的案例之后发现字数太多了,所以其它版本的五子棋将放在后续单独来写,敬请关注。

3.文中所提的SDK可在如下地址下载:

官网下载:www.gnxxkj.com

github下载:https://github.com/wangdechang119

gitlab下载:https://gitlab.com/wangdechang119

gitee下载:https://gitee.com/wangdechang119

你可能感兴趣的:(神经网络,人工智能,深度学习)