C++实现人机对战围棋(使用Leela Zero权重)-界面

1。在《leela-zero-next》包中有一个

从人类游戏训练的(较弱的)网络的权重文件(https://sjeng.org/zero/best_v1.txt.zip)(6残差块,128通道)

2。并在《easyx吧》百度贴吧下了一个双人对战的五子棋+围棋的游戏(去掉其中的五子棋部分)。

把这两个合成一个人机对战围棋。

虽然leela-zero也是C++写的,但是我也看不懂,这里只使用其权重,还是按前面的方法生成推演网络。

难点在

(1)围棋界面的部分的数组数据--->转换成网络输入

(2)网络输出--->转换界面落子位

界面部分

流程:

       载入一张背景图,在其上画19x19棋盘。

       然后在鼠标点位下子(黑白轮流下)(鼠标左键)(任何时都可以双方交换子)

       把其中的一方由网络代替

       提子要手工提(鼠标右键)

 

      一些变量:

int player_exchange = 0;//玩家轮流下棋
int arr[19][19] = { 0 };//棋盘数组
char str[5];//outtextxy转换字符中间容器
int a, b;//全局变量,记录交叉点位置
int a1, b1, a2, b2;//记录落子时落在数组的什么位置
int x, y;//全局变量,记录交叉点坐标

int record_now_player_exchange;//记录刚读档的exchange值,此后exchange就会++
int play_weiqi = 0;//是否选择围棋

//-------------------------------------
//人机对战
int jibw=0;//机器选黑白子 白:0,黑:1
vector 顺序黑;//黑方下子序号(在网络图中的序号(也是下子顺序),连接界面和网络用)
vector 顺序白;//白方下子序号

画棋盘:

// 画棋盘
void 画棋盘()
{
	int i;
	int j;

	BeginBatchDraw();

	IMAGE bk;
	loadimage(&bk, "围棋背景.jpg", 1100, 1000);

	//五子棋背景图片
	putimage(0, 0, 20 * 25 + 130, 121 * 25 - 20, &bk, 0, 0);
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 1);

	for (j = 1; j <= 19; j++)
	{
		line(1 * 25, j * 25, 19 * 25, j * 25);
	}
	for (i = 1; i <= 19; i++)
	{
		line(i * 25, 1 * 25, i * 25, 19 * 25);
	}
	//写入下标数字
	for (i = 1; i <= 19; i++)
	{
		for (j = 1; j <= 19; j++)
		{
			setbkmode(0);
			settextstyle(16, 0, _T("宋体"));
			settextcolor(BLACK);
			outtextxy(i * 25 - 6, 19 * 25 + 8, change(i));
			outtextxy(1 * 25 - 24, j * 25 - 9, change(j));
		}
	}
	//画边框
	setlinestyle(PS_SOLID, 2);
	line(1 * 25, 1 * 25, 19 * 25, 1 * 25);
	line(1 * 25, 19 * 25, 19 * 25, 19 * 25);
	line(1 * 25, 1 * 25, 1 * 25, 19 * 25);
	line(19 * 25, 1 * 25, 19 * 25, 19 * 25);
	setfillcolor(BLACK);
	//画四个点
	fillcircle(4 * 25, 4 * 25, 3);
	fillcircle(16 * 25, 4 * 25, 3);
	fillcircle(4 * 25, 16 * 25, 3);
	fillcircle(16 * 25, 16 * 25, 3);
	fillcircle(10 * 25, 10 * 25, 3);
	fillcircle(10 * 25, 4 * 25, 3);
	fillcircle(16 * 25, 10 * 25, 3);
	fillcircle(10 * 25, 16 * 25, 3);
	fillcircle(4 * 25, 10 * 25, 3);
	setbkmode(0);
	settextstyle(16, 0, _T("宋体"));
	settextcolor(BLACK);
	outtextxy(510, 40, "棋子坐标为:");
	//outtextxy(520, 60, "  行  列");
	outtextxy(520, 60, "  列  行");
	outtextxy(510, 100, "该:");
	outtextxy(510, 130, "白棋步数:");
	outtextxy(510, 160, "黑棋步数:");
	outtextxy(510, 190, "围棋规则:");
	outtextxy(510, 210, "·右键摘子");
	outtextxy(510, 230, "·玩家判断输赢");
	//outtextxy(510, 260, "五子棋规则:");
	outtextxy(510, 280, "按下a:对换子");
	//outtextxy(510, 350, "按下1:暂停:");
	//outtextxy(510, 380, "按下2:存档:");
	//outtextxy(510, 410, "按下3:退出:");
	//outtextxy(510, 440, "按下4:悔棋:");

	EndBatchDraw();

}

画好的棋盘:

C++实现人机对战围棋(使用Leela Zero权重)-界面_第1张图片

 入口:

int main()
{
	initNet();//载入网络权重
	initgame();//画棋盘
	system ("title 围棋");
	player_down();//游戏循环(人机下子)
	closegraph();
	return 0;
}

 游戏循环:

//玩家落子 游戏循环
void player_down()
{
	int i;
	int j;

	MOUSEMSG m;//定义一个鼠标变量m
	hwnd = GetHWnd();
	while (1)
	{
		m = GetMouseMsg();
		//让棋子下在交叉点
		for (i = 1; i <= 19; i++)
		{
			for (j = 1; j <= 19; j++)
			{
				if ((abs(m.x - i * 25)<12) && (abs(m.y - j * 25)<12))
				{
					//记录下交叉点的位置
					a = i;
					b = j;
					x = i * 25;
					y = j * 25;
				}
			}
		}
		if(player_exchange % 2 ==jibw)
		{
			if(机器下子())
				落子();
		}
		else
		{
			//玩家下子
			if (m.uMsg == WM_LBUTTONDOWN)
			{
				huiqi_just_one = 1;//赋值为1,允许悔棋
				if (arr[a - 1][b - 1] != 0)
				{
					//MessageBox(hwnd, TEXT("此地已有子,请另择他地!"), "提示:", MB_OK);
					continue;
				}
				cout<<"玩家:"<

机器下子:

bool 机器下子()
{

	//黑白子下子顺序到后面
	
	//生成最近8步棋数据
	//走子方8步棋
	//非走子方8步棋
	//当前行棋方-----------这些到网络部分 netgo 生成

	//输入网络

	//返回落子位

	bool lu=false;//选点成功吗,不成功可能要当机了(可以加大,5个不够)
		
	vector 前5序号;

	netgo(顺序黑, 顺序白,前5序号);//去网络部分

	//返回下子序号生成棋盘位置
	for(int i=0;i<前5序号.size();i++)
	{
		int xy=前5序号[i];
		int b0=xy/19;
		int a0=xy%19;
		if(arr[a0][b0]== 0)
		{
			b=b0+1;
			a=a0+1;
			cout<<"机:"<

落子并生成下棋顺序:

//落子并生成下棋顺序
void 落子()
{

	if (player_exchange % 2 == 0)
	{
		setfillcolor(WHITE);
		solidcircle(x, y, 8);
		//此时的a,b就是交叉点的位置
		a1 = a - 1; b1 = b - 1;
		arr[a1][b1] = 1;
		number_white++;
		//设置图片遮盖字体
		setfillcolor(YELLOW);
		solidrectangle(580, 130, 595, 147);//步数
		solidrectangle(580, 100, 595, 120);//黑,白字
		solidrectangle(519, 60, 534, 77);//棋子坐标
		solidrectangle(551, 60, 566, 77);//坐标
		//setcolor(BLACK);
		setlinecolor(BLACK);
		outtextxy(580, 130, change(number_white));
		outtextxy(564, 100, ":黑");
		outtextxy(519, 60,change(a1+1));
		outtextxy(551, 60, change(b1+1));
		顺序白.push_back(a1+b1*19);
	}
	else
	{
		setfillcolor(BLACK);
		solidcircle(x, y, 8);
		//将黑棋的点的值都设置成为2
		a2 = a - 1; b2 = b - 1;
		arr[a2][b2] = 2;
		number_black++;
		//设置图片遮盖字体
		setfillcolor(YELLOW);
		solidrectangle(580, 160, 595, 177);
		solidrectangle(580, 100, 595, 120);
		solidrectangle(519, 60, 534, 77);//坐标
		solidrectangle(551, 60, 566, 77);//坐标
		//setcolor(BLACK);
		setlinecolor(BLACK);
		outtextxy(580, 160, change(number_black));
		outtextxy(564, 100, ":白");
		outtextxy(519, 60, change(a2+1));
		outtextxy(551, 60, change(b2+1));
		顺序黑.push_back(a2+b2*19);
	}
	player_exchange++;

}

界面部分不都是我写的(我修改了一部分代码,,加了一部分,部分原创),有兴趣的朋友可以去贴吧下载原始代码。

下了几步图:

C++实现人机对战围棋(使用Leela Zero权重)-界面_第2张图片

界面部分暂时结束。

你可能感兴趣的:(人机对战围棋)