為什麼下圍棋電腦會自動走棋
『壹』 電腦為什麼會下象棋
我是學計算機的,呵呵,其實這個問題很有趣的呢^_^
中國的象棋我還不是很清楚,我目前所知道的最牛的機子名叫【深藍】,戰勝了國際象棋大師【卡斯帕羅夫】,詳細資料如下
http://www.wst.net.cn/history/5.11/10.htm
其實,計算機本身是沒有隻能的,之所以他能夠擁有下棋的能力,是因為我們預先教會了他,通過程序語言,實現了我們跟計算機之前的對話,就好像我們告訴他:
如果別人走馬,你就走馬,如果別人走象,你就走象一樣……
在計算機中,是通過程序語言來實現的,格式是
if......then......
else if......then.......
就跟上面的如果怎麼樣就怎麼樣是一樣的了,這樣計算機就懂得在不同情況下如何處理了哦^_^
希望姐姐的解釋還比較清晰^_^
【補充來了】^_^
思路1,平均每方每步可有35種走法。50回合。
思路2,棋盤上90個點,各點可走的點。如車可以走到任意一點。
按照思路一的演算法 往多了算
一盤棋有50回合,也就是100步,每步有50種變化
一共的變化數就是50的100次方
就算少算一點
一盤棋有20回合,也就是40步,每步10種變化
一共的變化數是10的40次方
這個數也足夠大了,就是1後面跟著40個0
【也就是說,別人走了一步以後,你有多少種可能的走法,計算機會去計算,然後擇優錄取】
給你個演算法吧,我們實驗課上經常做這些^_^
#include "StdAfx.h"
#include "Calculate.h"
#include "MantisChessThink.h"
#include "string.h"
#include "stdio.h"
/*************************************************************************
把Think重新包裝一下,進行坐標變換,希望以後其他人的演算法的介面都採用這個函數
這樣的編譯出來的DLL可以直接替換原來的CChessThinker.dll
timespan是思考的限定時間,以毫秒為單位,時間不同可能導致不同的思考策略。
本程序中的演算法沒有使用這一變數。
**************************************************************************/
BOOL Calculate(char* map,int timespan,int& x1,int& y1,int& x2,int& y2)
{
//BOOL Thinking(int tmap[11][12],POINT tmanposition[32],int &tside,int &resultman, POINT &resultpoint);
int tmap[11][12];
POINT manpoint[32];
int side=(int)map[0]-48;
int resultman=32;
POINT resultpoint={0,0};
for (int i = 0; i < 11; i++)
{
for (int j = 0; j < 12; j++)
{
tmap[i][j] = 32;
}
}
for (int i = 0; i < 32; i++)
{
manpoint[i].x=0;
manpoint[i].y=0;
}
int length=(int)strlen(map);
int index = 1;
while (index < length)
{
int x =1 + ((int)map[index + 0]-48);//thinking的x從1到9
int y = 10 - ((int)map[index + 1]-48);//thinking的y從10到1
int color = (int)map[index + 2]-48;//0-RED,1-BLAVK
int type = (int)map[index + 3]-48;//0-6
int manIndex=0;
if (color==0)
{
switch (type)
{
case 0:
manIndex=0;
break;
case 1:
if (manpoint[1].x==0) manIndex=1;
else manIndex=2;
break;
case 2:
if (manpoint[3].x==0) manIndex=3;
else manIndex=4;
break;
case 3:
if (manpoint[5].x==0) manIndex=5;
else manIndex=6;
break;
case 4:
if (manpoint[7].x==0) manIndex=7;
else manIndex=8;
break;
case 5:
if (manpoint[9].x==0) manIndex=9;
else manIndex=10;
break;
case 6:
if (manpoint[11].x==0) manIndex=11;
else if (manpoint[12].x==0) manIndex=12;
else if (manpoint[13].x==0) manIndex=13;
else if (manpoint[14].x==0) manIndex=14;
else manIndex=15;
break;
}
}
else
{
switch (type)
{
case 0:
manIndex=16;
break;
case 1:
if (manpoint[17].x==0) manIndex=17;
else manIndex=18;
break;
case 2:
if (manpoint[19].x==0) manIndex=19;
else manIndex=20;
break;
case 3:
if (manpoint[21].x==0) manIndex=21;
else manIndex=22;
break;
case 4:
if (manpoint[23].x==0) manIndex=23;
else manIndex=24;
break;
case 5:
if (manpoint[25].x==0) manIndex=25;
else manIndex=26;
break;
case 6:
if (manpoint[27].x==0) manIndex=27;
else if (manpoint[28].x==0) manIndex=28;
else if (manpoint[29].x==0) manIndex=29;
else if (manpoint[30].x==0) manIndex=30;
else manIndex=31;
break;
}
}
manpoint[manIndex].x=x;
manpoint[manIndex].y=y;
tmap[x][y]=manIndex;
index += 4;
}
//ShowInt(side);
//ShowInt(resultman);
//ShowInt(resultpoint.x);
//ShowInt(resultpoint.y);
BOOL b=Think( tmap,manpoint,side,resultman,resultpoint);
if (b)
{
x1=manpoint[resultman].x-1;
y1=10-manpoint[resultman].y;
x2=resultpoint.x-1;
y2=10-resultpoint.y;
}
return b;
//return FALSE;
}
BOOL test(char* x1)
{
return FALSE;
}
void ShowInt(int i)
{
char buf[256];
sprintf(buf,"%d",i);
MessageBox(NULL,buf,"test",0);
}
void ShowString(char * t)
{
MessageBox(NULL,t,"test",0);
}
/ CChessThink.cpp : 定義 DLL 應用程序的入口點。
//
#include "stdafx.h"
#ifdef _MANAGED
#pragma managed(push, off)
#endif
BOOL APIENTRY DllMain( HMODULE hMole,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
Calculate.h
void ShowInt(int i);
void ShowString(char * t);
BOOL Calculate(char* map,int timespan,int& x1,int& y1,int& x2,int& y2);
MantisChessDef.h
const int MW=32,SW=1; //MW-棋子寬度;SW-棋子間隔的一半
const int BWA=MW+SW*2; //BWA-棋格寬度
const int XBW=BWA*9,YBW=BWA*10; //棋盤的長寬
const int MAN=0; //人
const int COM=1; //計算機
const int RED=0; //紅方
const int BLACK=1; //黑方
const int RED_K=0; //紅帥
const int RED_S=1; //仕
const int RED_X=2; //相
const int RED_M=3; //馬
const int RED_J=4; //車
const int RED_P=5; //炮
const int RED_B=6; //兵
const int BLACK_K=7; //黑將
const int BLACK_S=8; //士
const int BLACK_X=9; //象
const int BLACK_M=10; //馬
const int BLACK_J=11; //車
const int BLACK_P=12; //炮
const int BLACK_B=13; //卒
//以下是全局函數定義:
//把棋子序號轉換為對應圖標的序號
const int ManToIcon[33]= {0,1,1,2,2,3,3,4,4,5,5,6,6,6,6,6
,7,8,8,9,9,10,10,11,11,12,12,13,13,13,13,13,-1};
//棋子類型與圖標的序號相同
#define ManToType ManToIcon
const int ManToType7[33]= {0,1,1,2,2,3,3,4,4,5,5,6,6,6,6,6
,0,1,1,2,2,3,3,4,4,5,5,6,6,6,6,6,-1};
//隨即函數,返回小於n的隨機整數
int rnd(const int& n);
//給出棋子序號!!,判斷是紅是黑
const int SideOfMan[33]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1};
const int _defaultmap[11][12]=
{
// [0][1][2][3][4][5][6][7][8][9][10][11]
{32,32,32,32,32,32,32,32,32,32,32,32},//[0]
{32,32,32,32,32,32,32,32,32,32,32,32},//[1]
{32,32,32,32,32,32,32,32,32,32,32,32},//[2]
{32,32,32,32,32,32,32,32,32,32,32,32},//[3]
{32,32,32,32,32,32,32,32,32,32,32,32},//[4]
{32,32,32,32,32,32,32,32,32,32,32,32},//[5]
{32,32,32,32,32,32,32,32,32,32,32,32},//[6]
{32,32,32,32,32,32,32,32,32,32,32,32},//[7]
{32,32,32,32,32,32,32,32,32,32,32,32},//[8]
{32,32,32,32,32,32,32,32,32,32,32,32},//[9]
{32,32,32,32,32,32,32,32,32,32,32,32}//[10]
};
const int FistOfSide[2]={0,16};
const int LastOfSide[2]={15,31};
const int MAXMOVE = 1000;
struct MOVEHISTORY
{
int count;
int man[MAXMOVE];
POINT from[MAXMOVE];
POINT to[MAXMOVE];
int betaken[MAXMOVE];
};
#include "StdAfx.h"
#include "MantisChessDef.h"
#include "MantisChessThink.h"
//-------------下面幾項可以調試智能模塊---------------------------
#define S_WIDTH 8
#define S_DEPTH 6
// 將 士 象 馬 車 炮 兵
const int base[7]= {300,400,300,600, 1000,600,300}; //平均價值
const int range[7]= {0 , 0, 0, 20, 10, 0, 50}; //價值的變動范圍
const int contactpercent1=20; //防守的重視程度
const int contactpercent2=25; //進攻的重視程度
/******************************************************************
例:把馬設為平均價值200,變動范圍±13%應設base[3]=200,range[3]=13
*******************************************************************/
//-----------------------------------------------------------------
const int BV1[7]=//基本價值
{
base[0]-base[0]*range[0]/100,
base[1]-base[1]*range[1]/100,
base[3]-base[2]*range[2]/100,
base[3]-base[3]*range[3]/100,
base[4]-base[4]*range[4]/100,
base[5]-base[5]*range[5]/100,
base[6]-base[6]*range[6]/100
};
const int BV2[7]=//活躍度
{
2*base[0]*range[0]/100/4,
2*base[1]*range[1]/100/4,
2*base[2]*range[2]/100/4,
2*base[3]*range[3]/100/8,
2*base[4]*range[4]/100/17,
2*base[5]*range[5]/100/17,
0,
};
const int BV3[5]=//兵在不同位置的價值附加
{
0*2*base[6]*range[6]/100/4,
1*2*base[6]*range[6]/100/4,
2*2*base[6]*range[6]/100/4,
3*2*base[6]*range[6]/100/4,
4*2*base[6]*range[6]/100/4,
};
#define NORED(i,j) (SideOfMan[tmap[i][j]]!=0)
#define NOBLACK(i,j) (SideOfMan[tmap[i][j]]!=1)
#define NOMAN(i,j) (tmap[i][j]==32)
//兵卒在不同位置的價值,數字越大價值越高
const int ManBPlus[2][12][11]=
{
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 1, 2, 3, 4, 4, 4, 3, 2, 1, 0},
{ 0, 1, 2, 3, 4, 4, 4, 3, 2, 1, 0},
{ 0, 1, 2, 3, 3, 3, 3, 3, 2, 1, 0},
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
{ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
},
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0},
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
{ 0, 1, 2, 3, 3, 3, 3, 3, 2, 1, 0},
{ 0, 1, 2, 3, 4, 4, 4, 3, 2, 1, 0},
{ 0, 1, 2, 3, 4, 4, 4, 3, 2, 1, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}
};
//-------------------------------------------
static void ContactV(int tmap[11][12],POINT tmanposition[32],int &tside,int activity[32],int contact[32][32]);
/******************************************************************
Mantis_QuickSort:對走法列表進行快速排序
參數:
A: 關鍵值
chessman: 待排序的棋子列表
targetpoint: 待排序的目標點列表
low,high: QuickSort上下限
返回值: 無
******************************************************************/
void Mantis_QuickSort(int A[],int chessman[],POINT targetpoint[],int low,int high)
{
int pivot;
int pivot_man;
POINT pivot_point;
int scanUp,scanDown;
int mid,k;
POINT point;
if(high-low<=0)
{
return;
}
else
{
if(high-low==1)
{
if(A[high]>A[low])
{
k=A[high];
A[high]=A[low];
A[low]=k;
k=chessman[high];
chessman[high]=chessman[low];
chessman[low]=k;
point=targetpoint[high];
targetpoint[high]=targetpoint[low];
targetpoint[low]=point;
return;
}
}
}
mid=(low +high)/2;
pivot=A[mid];
pivot_man=chessman[mid];
pivot_point=targetpoint[mid];
k=A[mid];
A[mid]=A[low];
A[low]=k;
k=chessman[mid];
chessman[mid]=chessman[low];
chessman[low]=k;
point=targetpoint[mid];
targetpoint[mid]=targetpoint[low];
targetpoint[low]=point;
scanUp =low+1;
scanDown = high;
do{
while(scanUp<=scanDown && A[scanUp]>=pivot)
scanUp++;
while(pivot>A[scanDown])
scanDown--;
if(scanUp<scanDown)
{
k=A[scanUp];
A[scanUp]=A[scanDown];
A[scanDown]=k;
k=chessman[scanUp];
chessman[scanUp]=chessman[scanDown];
chessman[scanDown]=k;
point=targetpoint[scanUp];
targetpoint[scanUp]=targetpoint[scanDown];
targetpoint[scanDown]=point;
}
}while(scanUp<scanDown);
A[low]=A[scanDown];
A[scanDown]=pivot;
chessman[low]=chessman[scanDown];
chessman[scanDown]=pivot_man;
targetpoint[low]=targetpoint[scanDown];
targetpoint[scanDown]=pivot_point;
if(low<scanDown-1)
Mantis_QuickSort(A,chessman,targetpoint,low,scanDown-1);
if(scanDown+1<high)
Mantis_QuickSort(A,chessman,targetpoint,scanDown+1,high);
}
/******************************************************************
Value: 估值函數
參數:
tmap: 各棋位狀態
tmanposition: 32棋子的坐標
tside: 輪到哪一放走
返回值: 局面的價值
******************************************************************/
int Value(int tmap[11][12],POINT tmanposition[32],int &tside)
{
static int k;
static int ManExtValue[32];
static int ManBaseValue[32];
static int ManContact[32][32];
static int BeAteCount[32];
static BOOL OwnSee[32];
ZeroMemory(ManContact,sizeof(int)*32*32);
ZeroMemory(ManBaseValue,sizeof(int)*32);
ZeroMemory(ManExtValue,sizeof(int)*32);
ZeroMemory(BeAteCount,sizeof(int)*32);
ZeroMemory(OwnSee,sizeof(int)*32);
int maxvalue=0;
int i,j;
ContactV(tmap,tmanposition,tside,ManBaseValue,ManContact);
//己方將軍
for(i=FistOfSide[tside];i<=LastOfSide[tside];i++)
{
if(ManContact[i][FistOfSide[!tside]])
{
maxvalue=9700;
return maxvalue;
}
}
for(i=0;i<32;i++)
{
k=ManToType7[i];
ManBaseValue[i]=BV1[k]+ManBaseValue[i]*BV2[k];
switch(k)
{
case 6: ManBaseValue[i]+=BV3[ ManBPlus[SideOfMan[i]][tmanposition[i].y][tmanposition[i].x] ];
break;
}
}
for(i=0;i<32;i++)
{
for(j=0;j<32;j++)
{
if(ManContact[i][j])
{
if(SideOfMan[i]==SideOfMan[j])
{
BeAteCount[j]++;
if(!OwnSee[j])
{
ManExtValue[i]+=ManBaseValue[j]*contactpercent1/100;//己方
OwnSee[j]=TRUE;
}
}
else
{
ManExtValue[i]+=ManBaseValue[j]*contactpercent2/100;//對方
BeAteCount[j]--;
}
}
}
}
for(i=FistOfSide[tside];i<=LastOfSide[tside];i++)
{
if(tmanposition[i].x)maxvalue+=ManBaseValue[i]+ManExtValue[i];
}
static BOOL flag;
flag=FALSE;k=32;
for(i=FistOfSide[!tside];i<=LastOfSide[!tside];i++)
{
if(tmanposition[i].x)maxvalue-=ManBaseValue[i]+ManExtValue[i];
//對方將軍
if(ManContact[i][FistOfSide[tside]])
{
flag=TRUE;
k=i;
break;
}
}
if(flag&&BeAteCount[k]>=0)//被將,所將軍的棋子不能被吃掉
{
j=0;
for(i=FistOfSide[tside];i<=LastOfSide[tside];i++)
{
if(BeAteCount[i]<0 && ManBaseValue[i]>j)
j=ManBaseValue[i];
}
maxvalue -=j;
}
else
{
j=0;
for(i=FistOfSide[!tside];i<=LastOfSide[!tside];i++)
{
if(BeAteCount[i]<0 && ManBaseValue[i]>j)
j=ManBaseValue[i];
}
maxvalue +=j;
}
return maxvalue;
}
/******************************************************************
EnumList: 列出所有走法
參數:
tmap: 各棋位狀態
tmanposition: 32棋子的坐標
tside: 輪到哪一放走
chessman: 指向棋子列表的指針(存放結果)
move: 指向棋子所走到位置的指針,與chessman一起組成走法列表
(存放結果)
count: 走法的總數(存放結果)
返回值: 「照相」返回TRUE,否則返回FALSE
******************************************************************/
BOOL EnumList(int tmap[11][12],POINT tmanposition[32],int &tside,int *chessman,POINT *move,int &count)
{
#define ADD(man,tx,ty) {chessman[count]=man;move[count].x=tx;move[count].y=ty;count++;if(tmap[tx][ty]==FistOfSide[!tside])goto _NOKING;}
static int i,j,n,x,y;
static BOOL flag;
count=0;
for(n=FistOfSide[tside];n<=LastOfSide[tside];n++)
{
x=tmanposition[n].x;
if(!x)continue;
y=tmanposition[n].y;
switch(n)
{
case 0:
if(tmanposition[0].x==tmanposition[16].x) //將帥在同一列
{
flag=FALSE;
for(j=tmanposition[16].y+1;j<tmanposition[0].y;j++)
{
if(tmap[x][j]!=32)
{
flag=TRUE;
break;
}
}
if (!flag)
{
ADD(0,x,tmanposition[16].y);
}
}
j=y+1;if(j<=10 && NORED(x,j)) ADD(0,x,j)
j=y-1;if(j>=8 && NORED(x,j)) ADD(0,x,j)
i=x+1;if(i<=6 && NORED(i,y)) ADD(0,i,y)
i=x-1;if(i>=4 && NORED(i,y)) ADD(0,i,y)
break;
case 16:
if(tmanposition[0].x==tmanposition[16].x) //將帥在同一列
{
flag=FALSE;
for(j=tmanposition[16].y+1;j<tmanposition[0].y;j++)
{
if(tmap[x][j]!=32)
{
flag=TRUE;
break;
}
}
if (!flag)
{
ADD(16,x,tmanposition[0].y);
}
}
j=y+1;if(j<=3 && NOBLACK(x,j)) ADD(16,x,j)
j=y-1;if(j>=1 && NOBLACK(x,j)) ADD(16,x,j)
i=x+1;if(i<=6 && NOBLACK(i,y)) ADD(16,i,y)
i=x-1;if(i>=4 && NOBLACK(i,y)) ADD(16,i,y)
break;
case 1:
case 2:
i=x+1;j=y+1;if(i<=6 && j<=10 && NORED(i,j)) ADD(n,i,j)
i=x+1;j=y-1;if(i<=6 && j>=8 && NORED(i,j)) ADD(n,i,j)
i=x-1;j=y+1;if(i>=4 && j<=10 && NORED(i,j)) ADD(n,i,j)
i=x-1;j=y-1;if(i>=4 && j>=8 && NORED(i,j)) ADD(n,i,j)
break;
case 17:
case 18:
i=x+1;j=y+1;if(i<=6 && j<=3 && NOBLACK(i,j)) ADD(n,i,j)
i=x+1;j=y-1;if(i<=6 && j>=1 && NOBLACK(i,j)) ADD(n,i,j)
i=x-1;j=y+1;if(i>=4 && j<=3 && NOBLACK(i,j)) ADD(n,i,j)
i=x-1;j=y-1;if(i>=4 && j>=1 && NOBLACK(i,j)) ADD(n,i,j)
break;
case 3:
case 4:
i=x+2;j=y+2;if(i<=9 && j<=10 && NORED(i,j)) if(NOMAN(x+1,y+1)) ADD(n,i,j)
i=x+2;j=y-2;if(i<=9 && j>=6 && NORED(i,j)) if(NOMAN(x+1,y-1)) ADD(n,i,j)
i=x-2;j=y+2;if(i>=1 && j<=10 && NORED(i,j)) if(NOMAN(x-1,y+1)) ADD(n,i,j)
i=x-2;j=y-2;if(i>=1 && j>=6 && NORED(i,j)) if(NOMAN(x-1,y-1)) ADD(n,i,j)
break;
case 19:
case 20:
i=x+2;j=y+2;if(i<=9 && j<=5 && NOBLACK(i,j)) if(NOMAN(x+1,y+1)) ADD(n,i,j)
i=x+2;j=y-2;if(i<=9 && j>=1 && NOBLACK(i,j)) if(NOMAN(x+1,y-1)) ADD(n,i,j)
i=x-2;j=y+2;if(i>=1 && j<=5 && NOBLACK(i,j)) if(NOMAN(x-1,y+1)) ADD(n,i,j)
i=x-2;j=y-2;if(i>=1 && j>=1 && NOBLACK(i,j)) if(NOMAN(x-1,y-1)) ADD(n,i,j)
break;
case 5:
case 6:
i=x+1;
if(NOMAN(i,y))
{
i=x+2;j=y+1;if(i<=9 && j<=10 && NORED(i,j)) ADD(n,i,j)
i=x+2;j=y-1;if(i<=9 && j>=1 && NORED(i,j)) ADD(n,i,j)
}
i=x-1;
if(NOMAN(i,y))
{
i=x-2;j=y+1;if(i>=1 && j<=10 && NORED(i,j)) ADD(n,i,j)
i=x-2;j=y-1;if(i>=1 && j>=1 && NORED(i,j)) ADD(n,i,j)
}
j=y+1;
if(NOMAN(x,j))
{
i=x+1;j=y+2;if(i<=9 && j<=10 && NORED(i,j)) ADD(n,i,j)
i=x-1;j=y+2;if(i>=1 && j<=10 && NORED(i,j)) ADD(n,i,j)
}
j=y-1;
if(NOMAN(x,j))
{
i=x+1;j=y-2;if(i<=9 && j>=1 && NORED(i,j)) ADD(n,i,j)
i=x-1;j=y-2;if(i>=1 && j>=1 && NORED(i,j)) ADD(n,i,j)
}
break;
case 21:
case 22:
i=x+1;
if(NOMAN(i,y))
{
i=x+2;j=y+1;if(i<=9 && j<=10 && NOBLACK(i,j)) ADD(n,i,j)
i=x+2;j=y-1;if(i<=9 && j>=1 && NOBLACK(i,j)) ADD(n,i,j)
}
i=x-1;
if(NOMAN(i,y))
{
i=x-2;j=y+1;if(i>=1 && j<=10 && NOBLACK(i,j)) ADD(n,i,j)
i=x-2;j=y-1;if(i>=1 && j>=1 && NOBLACK(i,j)) ADD(n,i,j)
}
j=y+1;
if(NOMAN(x,j))
{
i=x+1;j=y+2;if(i<=9 && j<=10 && NOBLACK(i,j)) ADD(n,i,j)
i=x-1;j=y+2;if(i>=1 && j<=10 && NOBLACK(i,j)) ADD(n,i,j)
}
j=y-1;
if(NOMAN(x,j))
{
i=x+1;j=y-2;if(i<=9 && j>=1 && NOBLACK(i,j)) ADD(n,i,j)
i=x-1;j=y-2;if(i>=1 && j>=1 && NOBLACK(i,j)) ADD(n,i,j)
}
break;
case 7:
case 8:
i=x+1;
while(i<=9)
{
if (NOMAN(i,y)) ADD(n,i,y)
else
{
if(NORED(i,y)) ADD(n,i,y)
break;
}
i++;
}
i=x-1;
while(i>=1)
{
if (NOMAN(i,y)) ADD(n,i,y)
else
{
if(NORED(i,y)) ADD(n,i,y)
break;
}
i--;
}
j=y+1;
while(j<=10)
{
if (NOMAN(x,j)) ADD(n,x,j)
else
{
if(NORED(x,j)) ADD(n,x,j)
break;
}
j++;
}
j=y-1;
while(j>=1)
{
if (NOMAN(x,j)) ADD(n,x,j)
else
{
if(NORED(x,j)) ADD(n,x,j)
break;
}
j--;
}
break;
case 23:
case 24:
i=x+1;
while(i<=9)
{
if (NOMAN(i,y)) ADD(n,i,y)
else
{
if(NOBLACK(i,y)) ADD(n,i,y)
break;
}
i++;
}
i=x-1;
while(i>=1)
{
if (NOMAN(i,y)) ADD(n,i,y)
else
{
if(NOBLACK(i,y)) ADD(n,i,y)
break;
}
i--;
}
j=y+1;
while(j<=10)
{
if (NOMAN(x,j)) ADD(n,x,j)
else
{
if(NOBLACK(x,j)) ADD(n,x,j)
break;
}
j++;
}
j=y-1;
while(j>=1)
{
if (NOMAN(x,j)) ADD(n,x,j)
else
{
if(NOBLACK(x,j)) ADD(n,x,j)
break;
}
j--;
}
break;
case 9:
case 10:
i=x+1;flag=FALSE;
while(i<=9)
{
if(NOMAN(i,y))
{
if(!flag) ADD(n,i,y)
}
else
{
if(!flag)flag=TRUE;
else
{
if(NORED(i,y)) ADD(n,i,y)
break;
}
}
i++;
}
i=x-1;flag=FALSE;
while(i>=1)
{
if(NOMAN(i,y))
{
if(!flag) ADD(n,i,y)
}
else
{
if(!flag)flag=TRUE;
else
{
if(NORED(i,y)) ADD(n,i,y)
break;
}
}
i--;
}
j=y+1;flag=FALSE;
while(j<=10)
{
if(NOMAN(x,j))
{
if(!flag) ADD(n,x,j)
【我是學c++的】呵呵,加了注釋,你應該能明白一點^_^
『貳』 為什麼ai圍棋天下無敵,但象棋就不行
象棋變化相對較少,計算機通過窮舉的方式就可以贏人類了,所以很早之前還沒出現AI時人類就下不過計算機了,能夠窮舉變化,那象棋在計算機眼裡就一覽無遺,沒有東西可以深挖了,也就沒有再做深入研究了。攻克了這個堡壘,目標就變成下一個了,那就是圍棋,圍棋變化繁多,用窮舉的方式行不通了,於是就要尋求演算法上的突破,好比玄幻小說中的等級,等級一旦突破,高一階就可以碾壓低一階,由於還不知道圍棋的極限在哪,所以AI還能持續進化,人類只會被越甩越遠。
1997年以前,人類勉強可以自欺欺人的說,人工智慧不足以挑戰頂尖象棋大師。但是1997年以後,電腦足以無差別碾壓任何一位人類象棋天才。
1996年,電腦cpu還是從486向奔騰邁進的年代,國際巨頭ibm打造了一台超級計算機,深藍。向當時國際象棋界無可爭議的第一人卡斯帕羅夫發起挑戰。那是如同喬丹在籃球場一樣的具有絕對統治力的存在。深藍落敗。
1997年,經過改良的更深的藍卷土重來,與卡斯帕羅夫手談數局,攻克了這位國際象棋的最巔峰棋手。
猶記得那時有國內媒體驕傲的宣稱,代表中國智慧的圍棋復雜程度在量級上遠超象棋,是電腦極難攻克的智力競技項目。
國際晶元巨頭英特爾的創始人摩爾經過觀察和總結,提出了著名的摩爾定律,即每隔十八個月,電腦的運算速度快一倍。
時間來到21世紀10年代,人工智慧先後擊敗了代表圍棋界最強實力的李世石和柯潔。從此,人類的任何棋類運動在電腦面前毫無勝算。這配渣滲其中,當然也包括中國象棋。
當今中國象棋第一人王天一,類似於c羅之於足球的存在,在電腦軟體面前毫無招架之力。
現在,無論圍棋還是象棋,用軟體拆招練習的人,勝負感更敏銳,招法更新穎,成績也更好。這也是棋類競技項目中,電腦勝過人類的有力佐證。
從 游戲 角度分析,象棋的核心目標是將軍,將死王之後 游戲 結束。而圍棋的核心目標則是圍到更大的空,這個在很多圍棋入門介紹視頻中也在反復提到,但這個定義過於抽象,導致很多人都摸不到頭腦,這個還和形式判斷有關。
象棋的入門相對圍棋要高一點,有七種不同的子,走法不同,而且還有河和宮的概念,其中將士不出宮,將士象不過河,兵過河可以橫著走。
而圍棋的入門其實更簡單,兩人交叉落子,落子不動,氣盡而亡,兩眼活棋(禁著點)。同時還有防止loop的打劫規則(象棋中其實也有對應的長將和不能行子判負的規則)
當然真正學圍棋的不會把這些當作入門,他們會學習大量死活,行棋方向,手筋,收官,定式等。學完這些他們才算入門。而象棋玩家學完上面那些真的可以開始玩了。
象棋其實更像是rpg 游戲 ,你帶領你的16位小夥伴去打怪,他們各有各自的能力,目標是殺死對面玩家(將/帥)這個會不會都可以開,無非是玩的好還是不好的區別。
而圍棋更像是回合制的rts(即時戰略)需要前期發展(定式)中期對戰和廝殺(中盤)以及簽訂戰後協議,劃分最後地盤(收官)。雖然 游戲 早期rts本身的競技性讓它曾經風靡一時,但這幾年還火的rts其實也沒幾個了。而且圍棋的中盤廝殺更像是一道大型解迷,這種需要動腦子的活動還是很難普及的。
因為象棋和圍棋的難度不同,象棋本身就得到了極大的普及,而且象棋畫幾個格子,拿幾個瓶蓋就能玩,在中國建國時物資還不充足時,一種好玩而且成本低的運動必然會受到許多人的追捧。而圍棋就算成本再低,幾百個有區分度的兩種不同顏色的棋子總得有吧。所以你會在大街上,看到那些老大爺下象棋的多,這可能還與圍棋不好攜帶有關,當然我們還說麻將也不好攜帶呢,為啥麻將普及度那麼高呢?我們還要提到另一個原因。
一種 游戲 的普及,尤其是一種需要操作和意識的競技 游梁殲戲 。往往一些比賽會帶動觀眾的情緒和熱情,不論是足球還是籃球,即使你不懂他們的規則,你也會在觀看中知道這邊把球丟進了框里得一分。像是電競最近仍比較火熱得lol,即使你沒玩過,也會知道這個塔倒了,這個人被殺死了。象棋就具備這種培脊最直觀得體驗,少個車,丟個馬還是能看出來勝負的。
而圍棋,天然缺失這種優勢。如果你不懂圍棋,你看比賽就是一臉懵。就拿你不能要求一個聽音樂會的,至少鋼琴入級。一個看電影的,至少得學過影視賞析,這不現實。而且早期圍棋還存在一個很致命的問題,參考柯潔和阿爾法下過的第二盤棋的解說,解說要麼看不懂雙方的好點,要麼是不擺變化(可能覺得無足輕重,但擺變化才是呈現棋手雙方復雜博弈的手段之一)講棋的已經是職業棋手了,但還是看不懂一些棋是好是壞,這個我們普通人就更難看懂了。
固然象棋在後續還有流派,學殺招,學行棋效率,但一切都是很明了的,哪步好哪步不好都是能判斷的,ai的出現只不過窮舉完象棋的變化,但象棋的路數其實也差不多到頭了,畢竟棋子數量就那麼多,實在不行用ai去走著試試。現在象棋比賽依舊存在,雙方的比拼點就是在比雙方對棋的理解誰更深了。而圍棋在阿爾法狗出現之前,對一些下法還存在很多爭議,其實比較多是定式的爭議,早期開局點三三是絕對的敗招,像《圍棋少年》中江流兒就下出過這樣一招,劇中說這是長輩對晚輩謙恭才下這個敗招,但ai時代也讓很多定式的有了不一樣的好壞定義。而現在看棋的人也不一定需要看講解的說辭了,自己用ai擺擺也能看出一步棋的好壞,解說的作用可能是告訴你這步為什麼好,畢竟觀眾不一樣。
除了ai時代才把棋的好壞逐漸講清楚這點外,圍棋的宣傳和教育方式也有問題。
宣傳上,圍棋是國粹,是一種高雅藝術,因為之前誰也講不清,所以還是門玄學 游戲 ,一直都和高智商和高境界掛在一起。但這個能讓圍棋活下去但不能讓圍棋活得很好。早期京劇是千人千面,是真正意義的市井藝術,為了賣座,還有很多的比較俗的藝術。這里的俗分通俗和低俗,通俗讓你聽懂,而低俗則是直接上來撓你癢,不管怎麼樣,觀眾進到劇場里了,才會知道京劇原來是這樣的,才會逐漸欣賞更雅一點的曲目。而現在京劇作為國粹,使得很多劇種都沒法演,觀眾想看要麼忍受一些不入流的京劇演員,要麼只能看老片子,這對京劇的發展不利。倒不如出一些像《三審伽利略》這樣的偏喜劇的京劇讓一些人入一下坑,不然京劇就是下一個崑曲。
而圍棋和京劇一樣,無論是文學作品裡的神乎奇技,還是和高雅人士掛鉤。其實都是其入門難,所有人都對其抱有神秘感,而且以前有心思琢磨圍棋的人都是有錢有閑的人,所以只在小眾圈子裡流傳,現在也差不多,只不過可以利用碎片化時間了而已。
中國圍棋的普及其實有幾個特殊時間點,一是聶衛平在日本的十幾連勝,當時只要中國在世界舞台上取得相當的成就,都會帶動國內的項目的普及和發展。比如籃球,乒乓球,足球(2002),排球等。而且當時圍棋入段能加分,很多人都送自己孩子去學棋,畢竟有提高智力之名。
之後可能就是棋魂和《圍棋少年》的火爆。雖然棋魂是我後續補的,不知道當時有多大的影響程度,但很多圍棋up都說自己是因為棋魂開始下圍棋的。而圍棋少年,雖然現在開始重新分析其作畫有問題,過於傲慢拒絕了棋手的影視指導,導致這部劇存在了很大的瑕疵,而且天地大同和天魔大化太過故弄玄虛,本身就像是兩個武林高手雙方比試重要的雙方的名字而不是真正的動作。其實更好的處理是在作畫上體現,但是原因看前一條。但不可否認的是,圍棋少年依舊是一部優秀的講棋心,講人情世故得動畫,如果你把它當作武俠片的話。
第三階段可能就是2016年的ai時代的來臨,曾經在科幻小說里出現的,人類堅守圍棋這片智力的最後高地,沒想到居然來的這么快。2015年時央視還出了個圍棋的記錄片,講ai要和人類一戰或許還要20年,沒想到才一年就殺得人類丟盔棄甲,彷彿世界末日就要到來。當時阿爾法狗還是學習人類棋譜訓練的,還會輸給李世石。才一年,自我學習的阿爾法狗zero就已誕生,甚至比之前還要強大數倍。之後,柯潔也在對局中敗給了再次進化的阿爾法狗master。其實在這之前master已經和60位棋手下過了,基本是全勝。當時的討論都是ai會不會統治人類,圍棋現在還有要學的必要,至此,圍棋可以說是脫去了神秘的面紗,關注度真正來到了頂峰。
之後是柯潔被狗打哭後連贏人類棋手十幾盤,棋手這時才判然醒悟,原來和ai學棋是對的,至此,圍棋不但沒有衰落,反而在路人中間獲得了極大的關注度,還提高了職業棋手和業余棋手的水平等級。加上柯潔本身是個很有爭議的人物,所有人都來關注他,雖然我相信很多人都不是來看圍棋的,但學圍棋的肯定是多了起來。人們對圍棋總算有了個更清晰的判斷。圍棋畢竟還是一個智力 游戲 。雖然有人提倡超脫於室外的道,但想下好圍棋,還是得磨好殺棋制勝的術。
至此,象棋的普及基於其本身戰爭 游戲 的抽象,同時又簡單上手,走街都能看到老大爺在下棋,普及度自然原超圍棋。而圍棋本身入門門檻較高,導致很多人都不願進門檻,但現在ai和網棋的發展,人們大可以和ai去學習圍棋,而不用報一些身份不明的圍棋班,對於一些小夥伴來說這也是加入圍棋的好機會(雖然肯定也不會很多就是了)
象棋AI早就吊打人類頂尖棋手了,只不過現在人類棋手也開始學習AI布局。加上象棋變化少,還有逼和下法;但是整體上還是不如AI。象棋現在已經發展出AI比賽,雙方比拼電腦硬體,軟體演算法還有最關鍵的是AI棋庫;最新的棋庫都是要收費的!網上有很多AI象棋比賽視頻,水平高人類選手一大截。各種精妙進攻搏殺,飛刀又見飛刀,刀刀致命!
笑死我了。
你知道象棋把世界冠軍贏了的那個年代,隨便一個圍棋小白都能把最強的圍棋AI打贏嗎?
現在隨便一個合格的人工智慧領域的計算機博士,都有能力開發出一個世界冠軍水平的象棋AI。
沒人做是因為已經過時了,搞象棋AI,就好比在21世紀干BB機維修。
到目前為止。我認為Al.邏輯思維。以及追趕變化的能力仍然是遠遠不夠的。象棋好像有個固定的路子。Al容易掌控。但對圍棋我沒有見過。更別說懂。但據分析,圍棋的路子不是固定的。靈活的變化性較大。所以Al.掌控不了。比如像磁動機的組合。Al是組合不出來的。不知我這樣評論Al.是否有一些道理?
象棋早就把人虐了,畢竟變化少,開局庫加上搜索幾乎能夠涵蓋所有的變化,而圍棋變化太多,靠開局庫和窮舉搜索是解決不了的!所以在alphago之前,最牛的圍棋軟體也就有個業餘五段水平!
從把深度學習(神經網路)引入圍棋以來,圍棋ai現在針對人而言,幾乎就是神一般的存在!
現在圍棋ai這么轟動,跟 社會 環境也有關系,現在整個 社會 都在熱炒ai,所以象棋就相形見絀了!其實leela zero的作者也把ai應用到國際象棋上了,只是國內沒大用!
說AI象棋不行的,說明你根本就沒了解過,都不用ai大牛阿爾法狗上陣,低端ai就能橫掃所有象棋高手了!!
相對圍棋來說,象棋的變化要少的多,對於ai而言更是簡單的多,需要的算力更是不可同日而語,人工智慧也就是最近這兩年才打敗頂級人類高手,而象棋早早就被攻克了!!!
現在象棋第一人是誰你知道不?這種問題也提。。。。
我認為這個問題是由於圍棋與象棋的區別造成的:
象棋對棋子的規則很多,而圍棋對棋子的規則很少。
從一開局,象棋的每一個棋子都必須按照規定,放置在固定的位置上。而且,對奕雙方的棋子數量和各亇棋子的作用是相同的。這就使象棋從一開始搏奕時,就有了思維基礎。對奕雙方就可以在這亇基礎上,進行通盤謀劃。
而圍棋沒有預設棋子的規定。開局後,對奕雙方你來我往,可以在棋盤上的任意一個點落子。而後,己經落下的棋子才成為固定位置上的棋子。而那些仍然掌握在雙方棋手中,還沒落到棋盤上的棋子,究竟會落在那亇點上成為固定棋子,對搏奕的雙方都是未知數。這就使圍棋相比象棋,從開局時就對通盤謀劃產生了極大的難度。
象棋對每一亇棋子的走棋方法有著嚴格的規定:「馬走日子象走田,車走直路一炮翻山,小卒攻的一杠煙,老將蹲在後花園」。因此,造成了各個棋子的作用和殺傷力大不相同。這亇規定,可以使棋手比較容易地通過對單個棋子的所在位置,走棋規定和作用,結合全盤考慮,計祘出自己和對方的下一步棋如何走。
而圍棋的棋子落在棋盤上任何一個點上後,就只能成為固定棋子,不得再挪動。因此,圍棋的棋子不存在棋子走棋方法的規定問題。這就使圍棋相比於象棋,減少了一個思維,判斷和計祘的依據。從而也就大大地增加了圍棋搏奕的難度。
象棋取勝的目標是吃掉對方的老將,簡單而又明確,貫穿於整亇搏奕過程中。為此,從開局始雙方就殺氣騰騰,對准取勝目標,通過進攻和防守,牽制和消滅對方的棋子,直至吃掉對方的老將。當雙方都無法吃掉對方老將時,只能握手言和。
圍棋取勝的目標是佔領比對方更多的「地盤」。而這個致勝的「地盤」究竟在那裡,從一開局就是不確定的,模糊的。只有在搏奕的過程中才能逐漸顯露出來。而在搏奕過程中雙方產生的各個「地盤」,都有可能成為取勝的致命目標。搏奕雙方在落下每一個棋子時,都要結合這些目標,全面考慮和計祘將要落下的這一亇棋子的得失。隨著棋盤上雙方棋子的增加,局面將會變得愈加復雜,取勝將會更難,顧此失彼的可能性很大。
象棋棋盤上的落子點只有90個,而圍棋棋盤上的落子點竟多達361亇。這種落子點的增多,大大增加了圍棋的變化程度和難度。
通過以上對比,顯而易見,圍棋需要的計祘難度遠遠高出於象棋。而象棋的計祘難度雖不及圍棋,卻規則繁多,需要較多的邏輯思維。而計祘機的優勢就在於計祘。隨著計祘機的發展,人類的計祘能力己遠不如計祘機。因此ai圍棋可以天下無敵,而象棋卻不行。
圍棋AI是使用的最近幾年很火的深度學習演算法來取勝的。象棋其實也早有軟體了,但是使用的不是深度學習,而是其他技術。
深度學習目前正在發展中,還有很多需要突破的難題,但是也有很多成熟的演算法。最典型的成熟演算法就是圖像處理。
而圍棋的規則,決定了它天生就是一幅「簡單」的圖像。圖像中,有19 19個像素。像素總共只有3種顏色:黑、白、黃(假設棋盤是黃的)。圍棋是比較偏「靜止」的,棋子落地生根,不允許再運動,最多就是提子。這些特點,使得看待圍棋局勢,就像看一幅圖一樣。這與象棋不同, 象棋很難當成圖像進行處理 。
象棋棋子太多,走子規則復雜,每個棋子與周邊棋子的聯系不像圍棋那樣簡單粗暴。看待圍棋「圖像」時,腦海中可以把某一大片黑子(或白子)連成片,當成一個整體。然後就變成了,看誰容易圍住誰,誰「實」多,誰「虛」多。這就是「圖像」。象棋則不行。比方說車馬炮就是不相乾的,很難連起來當一幅圖看。
深度學習,是人工智慧的一種,模擬的是人類的智能。按目前的技術,它 最接近人類不需要思考就能得立刻出結果的問題 。比方說人類識別一張人臉,是不需要思考的,靠「感覺」,而且用不了1秒鍾。但是又很難描述這種「感覺」。患有臉盲症的人很難感覺出人臉,他們需要通過思考來確定特徵(黑痣、發型、胡須等)。
人工智慧下圍棋,那就是有「棋感」。人類下圍棋時,運用「棋感」,就是說下一步棋時,不需要計算和過多思考,直接通過「圖像」的感覺直接走子。這在圍棋開局前幾十著特別常見。而計算是指,一步一步推演,比方說看看某條大龍能不能最終走活。
國際象棋的深藍軟體則不一樣,那個不叫棋感,而是絕大部分是精密復雜的數學運算。
以上只是為了簡單起見,提到了圍棋AI的「棋感」,而且強調人工智慧 目前 特別擅長處理類似圖像一類的問題。實際上,阿爾法狗使用了多個網路,其中一部分負責「棋感」,另外一部分還是需要計算的。其實,這和人類下棋就很像了,人類下棋也是棋感加計算相結合的。不過阿爾法狗的精華肯定是棋感那部分。人類又何嘗不是。稍微學過圍棋的,誰都會推演死活,但是依賴棋感的那些「神之一手」,以及判斷局勢,那才是大師與菜鳥的最大區別。
『叄』 計算機怎麼會下棋呢
1997年5月,紐約舉行了一場別開生面的國際象棋比賽,對陣雙方是世界冠軍卡斯帕羅夫和IBM公司的「深藍」超級並行計算機。最終,在全世界的矚目下,卡斯帕羅夫輸給了「深藍」,許多人因此感到人類將面臨前所未有的挑戰。要讓計算機能夠下棋,首先要用計算機語言把國際象棋的走法及下棋的一般規律編定為程序輸入計算機,這種規律能使計算機通過計敏姿洞算走子後的局面來選擇最佳落子方案。計算機除橋枯了掌握一般的應對招法,還要具有隨機應變的本領。計算機會在下棋過程中從自己的失敗中吸取教訓,從對手那裡吸取長處,積累經驗,不斷提高棋藝。這樣一來,如果計算機按冊羨照某種下法輸了棋,它就會吸取經驗,再次下棋時,計算機就會選擇新的走法,不再上當。