广工人工智能实验报告.docx
《广工人工智能实验报告.docx》由会员分享,可在线阅读,更多相关《广工人工智能实验报告.docx(20页珍藏版)》请在冰豆网上搜索。
广工人工智能实验报告
实验课程名称:
__人工智能
实验项目名称
井子棋AIalpha-beta剪枝算法
实验成绩
实验者
叶海恒
专业班级
计科8班
学号
3114006156
实验日期
2016.11
一、实验内容
设计具有AI的井子棋游戏(采用js)
AI采用α-β剪枝算法
二、实验设计(原理分析及流程)
min电脑AI下棋时,如果考虑步数为0,则代表直接返回当前棋盘估值w(值越大代表对max越有优势,越小则代表对min越有优势,w=maxW-minW)。
如果考虑步数为N,先获取min电脑可以下棋的位置steps。
对于可以下棋的一步step,电脑AI下棋到step的第row行,第column列。
如果这时候min电脑已经赢了,则把棋盘回退一步,返回棋盘估值和下棋位置,不用再考虑其他走法了。
否则,min需要在每一种走法里面,选择一种走法,令max人类走N-1步之后,自己的优势保持最大(即w值最小)。
什么是alpha-beta剪枝呢?
就是如果max人类当前一种走法1至少可以获取alpha优势,而另一种走法2,min电脑的一步棋则可能让人类获取比alpha更小的优势,那么max人类肯定不会选择走法2,所以计算在计算min电脑的走法时,min电脑的其他走法就不用再计算了。
最后min电脑经过steps.length种走法对比之后,选择w值最小的一种走法,把棋盘回退一步,并返回棋盘估值和下棋位置。
max走法类似,人类会选择w值最大的走法下棋,所以max函数和min函数分别代表人和AI下棋,互相递归调用,直到递归到步数为0时返回N步之后的估值。
三、实验代码及数据记录
1.代码
/**
*[Matrix矩阵]
*@param{[type]}arr[矩阵二维数组]
*/
varMatrix=function(arr){
this.data=arr;
this.row=arr.length;
this.column=arr.length?
arr[0].length:
0;
};
/**
*[multiply矩阵乘法转换]
*@param{[type]}matrix[转换矩阵]
*@return{[type]}[description]
*/
Matrix.prototype.multiply=function(matrix){
if(this.column==matrix.row){
varrow=this.row,
column=matrix.column,
arr=[];
for(vari=0;iarr[i]=[];
for(varj=0;jvarsum=0;
for(varn=0;nsum+=(this.data[i][n]*matrix.data[n][j]);
}
arr[i][j]=sum;
}
}
returnnewMatrix(arr);
}
};
/**
*[Chessboard棋盘]
*@param{[type]}row[description]
*@param{[type]}column[description]
*/
varChessboard=function(row,column){
this.data=[];
this.row=row;
this.column=column;
for(vari=0;ithis.data[i]=[];
for(varj=0;jthis.data[i][j]=Chessboard.NONE;
}
}
this.stack=[];
this.is_ended=false;
};
/**
*[toString输出棋盘信息]
*@return{[type]}[description]
*/
Chessboard.prototype.toString=function(){
returnthis.data.map(function(data){
returndata.toString();
}).join('\n');
};
/**
*[put下棋]
*@param{[type]}row[行]
*@param{[type]}column[列]
*@param{[type]}type[人还是AI下棋]
*@return{[type]}[description]
*/
Chessboard.prototype.put=function(row,column,type){
if(this.data[row][column]==Chessboard.NONE){
this.data[row][column]=type;
this.stack.push({
row:
row,
column:
column,
type:
type
});
if(this.stack.length==this.row*this.column){
this.is_ended=true;
}
}
returnthis;
};
/**
*[rollback悔棋]
*@param{[type]}n[后退n步]
*@return{[type]}[description]
*/
Chessboard.prototype.rollback=function(n){
n=n||1;
for(vari=0;ivarstep=this.stack.pop();
if(step){
this.data[step.row][step.column]=Chessboard.NONE;
}
}
this.is_ended=false;
returnthis;
};
/**
*[reset重置棋盘]
*@return{[type]}[description]
*/
Chessboard.prototype.reset=function(){
for(vari=0,n=this.row;ifor(varj=0,m=this.column;jthis.data[i][j]=Chessboard.NONE;
}
}
this.stack=[];
this.is_ended=false;
};
/**
*[availableSteps获取可走的位置]
*@return{[type]}[description]
*/
Chessboard.prototype.availableSteps=function(){
varavailableSteps=[];
for(vari=0,n=this.row;ifor(varj=0,m=this.column;jif(this.data[i][j]==Chessboard.NONE){
availableSteps.push({
row:
i,
column:
j
});
}
}
}
returnavailableSteps;
};
/**
*[rotate把棋盘旋转90度]
*@return{[type]}[description]
*/
Chessboard.prototype.rotate=function(){
varboard=newChessboard(this.row,this.column),
dx=Math.floor(this.column/2),
dy=Math.floor(this.row/2);
for(vari=0;ifor(varj=0;jvartype=this.data[i][j];
varmatrix=newMatrix([
[i,j,1]
]);
vartranslateMatrix1=newMatrix([
[1,0,0],
[0,1,0],
[-dx,-dy,1]
]);
vartranslateMatrix2=newMatrix([
[1,0,0],
[0,1,0],
[dx,dy,1]
]);
varrotateMatrix=newMatrix([
[0,-1,0],
[1,0,0],
[0,0,1]
]);
varres=matrix.multiply(translateMatrix1).multiply(rotateMatrix).multiply(translateMatrix2);
board.put(res.data[0][0],res.data[0][1],type);
}
}
returnboard;
};
/**
*[hash给棋盘一个编码]
*@param{[type]}sourceRadix[来源进制]
*@param{[type]}targetRadix[目的进制]
*@return{[type]}[description]
*/
Chessboard.prototype.hash=function(sourceRadix,targetRadix){
varstr=this.data.map(function(arr){
returnarr.join('');
}).join('');
returnparseInt(str,sourceRadix).toString(targetRadix);
};
/**
*[evaluate计算当前棋盘的估值]
*@return{[type]}[description]
*/
Chessboard.prototype.evaluate=function(){
//max,min权重,max连棋数,min连棋数
varmaxW=minW=0,
maxCount,minCount;
//横向计算
for(vari=0;i//当前这一行,max连棋数,min连棋数
maxCount=minCount=0;
for(varj=0;jvartype=this.data[i][j];
if(type==Chessboard.MAX){
maxCount++;
}else{
if(type==Chessboard.MIN){
minCount++;
}
}
}
//如果连成3子
if(maxCount==3){
returnInfinity;
}else{
if(minCount==3){
return-Infinity;
}else{
//如果没有max的棋子,则min可能连成3子
if(!
maxCount){
minW++;
}
//如果没有min的棋子,则max可能连成3子
if(!
minCount){
maxW++;
}
}
}
}
//纵向计算
for(vari=0;i//当前这一列,max连棋数,min连棋数
maxCount=minCount=0;
for(varj=0;jvartype=this.data[j][i];
if(type==Chessboard.MAX){
maxCount++;
}else{
if(type==Chessboard.MIN){
minCount++;
}
}
}
//如果连成3子
if(maxCount==this.row){
returnInfinity;
}else{
if(minCount==this.row){
return-Infinity;
}else{
//如果没有max的棋子,则min可能连成3子
if(!
maxCount){
minW++;
}
//如果没有min的棋子,则max可能连成3子
if(!
minCount){
maxW++;
}
}
}
}
//右斜下方向计算
maxCount=minCount=0;
for(vari=0;ivartype=this.data[i][i];
if(type==Chessboard.MAX){
maxCount++;
}else{
if(type==Chessboard.MIN){
minCount++;
}
}
}
//如果连成3子
if(maxCount==this.row){
returnInfinity;
}else{
if(minCount==this.row){
return-Infinity;
}else{
//如果没有max的棋子,则min可能连成3子
if(!
maxCount){
minW++;
}
//如果没有min的棋子,则max可能连成3子
if(!
minCount){
maxW++;
}
}
}
//左斜下方向计算
maxCount=minCount=0;
for(vari=0;ivartype=this.data[i][this.column-i-1];
if(type==Chessboard.MAX){
maxCount++;
}else{
if(type==Chessboard.MIN){
minCount++;
}
}
}
if(maxCount==this.row){
returnInfinity;
}else{
if(minCount==this.row){
return-Infinity;
}else{
//如果没有max的棋子,则min可能连成3子
if(!
maxCount){
minW++;
}
//如果没有min的棋子,则max可能连成3子
if(!
minCount){
maxW++;
}
}
}
//返回双方实力差
returnmaxW-minW;
};
/**
*[isMaxWin人是否赢了]
*@return{Boolean}[description]
*/
Chessboard.prototype.isMaxWin=function(){
varw=this.evaluate();
returnw==Infinity?
true:
false;
};
/**
*[isMinWinAI是否赢了]
*@return{Boolean}[description]
*/
Chessboard.prototype.isMinWin=function(){
varw=this.evaluate();
returnw==-Infinity?
true:
false;
};
/**
*[end结束游戏]
*@return{[type]}[description]
*/
Chessboard.prototype.end=function(){
this.is_ended=true;
returnthis;
};
/**
*[isEnded游戏是否结束]
*@return{Boolean}[description]
*/
Chessboard.prototype.isEnded=function(){
returnthis.is_ended;
};
/**
*[maxmax下棋]
*@param{[type]}currentChessboard[当前棋盘]
*@param{[type]}depth[考虑深度]
*@return{[type]}[description]
*/
varmax=function(currentChessboard,depth,beta){
//记录优势值,应该下棋的位置
varrow,column,alpha=-Infinity;
//什么都不下,直接返回当前棋盘评估值
if(depth==0){
alpha=currentChessboard.evaluate();
return{
w:
alpha
};
}else{
//获取每一步可以走的方案
varsteps=currentChessboard.availableSteps();
//console.log('搜索MAX'+steps.length+'个棋局');
if(steps.length){
//对于每一种走法
for(vari=0,l=steps.length;ivarstep=steps[i];
//下棋
currentChessboard.put(step.row,step.column,Chessboard.MAX);
//如果已经赢了,则直接下棋,不再考虑对方下棋
if(currentChessboard.isMaxWin()){
alpha=Infinity;
row=step.row;
column=step.column;
//退回上一步下棋
currentChessboard.rollback();
break;
}else{
//考虑对方depth-1步下棋之后的优势值,如果对方没棋可下了,则返回当前棋盘估值
varres=min(currentChessboard,depth-1)||{
w:
currentChessboard.evaluate()
};
//退回上一步下棋
currentChessboard.rollback();
if(res.w>alpha){
//选择最大优势的走法
alpha=res.w;
row=step.row;
column=step.column;
}
//如果人可以获得更好的走法,则AI必然不会选择这一步走法,所以不用再考虑人的其他走法
if(alpha>=beta){
//console.log('MAX节点'+l+'个棋局,剪掉了'+(l-1-i)+'个MIN棋局');
break;
}
}
}
return{
w:
alpha,
row:
row,
column:
column
};
}
}
};
/**
*[minmin下棋]
*@param{[type]}currentChessboard[当前棋盘]
*@param{[type]}depth[考虑深度]
*@return{[type]}[权重和当前推荐下棋的位置]
*/
varmin=function(currentChessboard,depth,alpha){
varrow,column,beta=Infinity;
if(depth==0){
beta=currentChessboard.evaluate();
return{
w:
beta
};
}else{
//获取每一步可以走的方案
varsteps=currentChessboard.availableSteps();
//console.log('搜索MIN'+steps.length+'个棋局');
if(steps.length){
//对于每一种走法
for(vari=0,l=steps.length;ivarstep=steps[i];
//下棋
currentChessboard.put(step.row,step.column,Chessboard.MIN);
//如果已经赢了,则直接下棋,不再考虑对方下棋
if(currentChessboard.isMinWin()){
beta=-Infinity;
row=step.row;
column=step.column;
//退回上一步下棋
currentChessboard.rollback();
break;
}else{
//考虑对方depth-1步下棋之后的优势值,如果对方没棋可下了,则返回当前棋盘估值
varres=max(currentChessboard,depth-1,beta)||{
w:
currentChessboard.evaluate()
};
//退回上一步下棋
currentChessboard.rollback();
if(res.w//选择最大优势的走法
|
|