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<int> 順序黑;//黑方下子序號(在網絡圖中的序號(也是下子順序),連接界面和網絡用)
vector<int> 順序白;//白方下子序號
畫棋盤:
// 畫棋盤
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();
}
畫好的棋盤:
入口:
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<<"玩家:"<<a<<","<<b<<endl;
cout<<"序號:"<<(b-1)*19+a-1<<endl;
落子();
}
}
//按下右鍵,清除棋子——圍棋規則
if (m.uMsg == WM_RBUTTONDOWN)
{
if (arr[a - 1][b - 1]!= 0)
{
arr[a - 1][b - 1] = 0;
delete_stone_youjian();
continue;
}
}
char ch;//接收鍵盤的變量
hwnd = GetHWnd();
while (kbhit())
{
ch = getch();
//玩家和機器對換
if (ch == 'a')
{
if(jibw==0)
jibw=1;
else
jibw=0;
}
}
}
}
機器下子:
bool 機器下子()
{
//黑白子下子順序到後面
//生成最近8步棋數據
//走子方8步棋
//非走子方8步棋
//當前行棋方-----------這些到網絡部分 netgo 生成
//輸入網絡
//返回落子位
bool lu=false;//選點成功嗎,不成功可能要當機了(可以加大,5個不夠)
vector<int> 前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<<"機:"<<a<<","<<b<<endl;
cout<<"序號:"<<xy<<endl;
x = a * 25;
y = b * 25;
lu=true;
break;
}
}
return lu;
}
落子並生成下棋順序:
//落子並生成下棋順序
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++;
}
界面部分不都是我寫的(我修改了一部分代碼,,加了一部分,部分原創),有興趣的朋友可以去貼吧下載原始代碼。
下了幾步圖:
界面部分暫時結束。