五子棋-AI-PK-AI.html  返回列表

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>五子棋-AI战AI.html</title>
<style type="text/css">
	table{ border:10px solid #cccccc;float:left;}
	.aiinfo{font-size:12px;float:left;width:300px; height:600px; background-color:#008080; border:10px solid #119191; color:#ffffff;}
	.aiinfo h1{ font-size:14px;}
	.td_pos{ position:relative;}
	.pos_top{ position:absolute; left:10px; top:0px; width:10px; height:10px; background-color:#DDEEFF; font-size:10px;}
	.pos_left{ position:absolute; left:0px; top:10px; width:10px; height:10px; background-color:#DDEEFF; font-size:10px;}
</style>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<script type="text/javascript">
	if(typeof window.console == 'undefined'){window.console={'log':function(){},'error':function(){}}}
	Number.prototype.toInt=function(){
		var num=parseInt(this);
		var reg=(this+'').match(/\.([0-9])(.*)/);
		if(reg && reg[1]>4){
			num+=1;
		}
		return num;
	}
	//AI
	var AI=function(checkerboard,userA,userB){
		this.depth=5;
		this.checkerboard=checkerboard;
		this.piece={};
		this.fourPos=[];
		this.userA= 'A';
		this.userB=	'B';
		this.memory={};
		this.memory[this.userA]={};
		this.memory[this.userB]={};
		this.eightBase=this.fixBoard(0).concat(this.fixBoard(45));
	}
	//根据角度构造4方向坐标
	AI.prototype.fixBoard=function(anglex){
		var PI2=Math.PI*2;
		anglex=typeof anglex=='undefined'?0:anglex;//角度
		var angle=anglex/PI2;
		var r=(anglex==0)?1:Math.sqrt(2);
		var points=[];
		for(var i=angle;i<PI2+angle;i+=PI2/4){
			var x=r*Math.cos(i);
			var y=r*Math.sin(i);
			points.push({
				x: x,
				y: y
			});
		}
		return points;
	}
	//根据棋子位置及八项基数构造八项坐标
	AI.prototype.makeEightPos=function(piece){
		var piece=piece || this.piece;
		var eightBase=this.eightBase;
		var eightPos=[];
		for (var j = 0; j < 8; j++) {
			eightPos[j]=[];
			eightPos[j][0]={x:piece.x,y:piece.y};
			var depth=this.depth;
			for(var i=1;i<=depth;i++){
				var x=eightBase[j].x*i+piece.x;
				var y=eightBase[j].y*i+piece.y;
				eightPos[j][i]={x:x.toInt(),y:y.toInt()};
				
			}
		}
		return eightPos;
	}
	
	//连接八项坐标构造四项坐标
	AI.prototype.makeFourPos=function(eightPos){
		var fourPos=[];
		for(var i=0;i<6;i++){
			if(i==2 || i==3) continue;
			eightPos[i].shift();
			fourPos.push((eightPos[i+2].reverse()).concat(eightPos[i]));
		}
		return fourPos;
	}
	AI.prototype.rivalUser=function(flag){
		return flag==this.userA?this.userB:this.userA;
	}
	//
	AI.prototype.check=function(piece){
		this.piece=piece;
		var eightPos=this.makeEightPos();
		this.fourPos=this.makeFourPos(eightPos);
		return this.checkVictory();
	}
	//
	AI.prototype.addMemory=function(pos,memory,userFlag){
		var pos=pos.x+'_'+pos.y;
		if(typeof this.memory[userFlag][pos]=='undefined') this.memory[userFlag][pos]=[];
		this.memory[userFlag][pos].push(memory);
		//console.log(this.memory);
	}
	AI.prototype.delMemory=function(pos,userFlag){
		var pos=pos.x+'_'+pos.y;
		this.memory[userFlag][pos]=[];
		delete this.memory[userFlag][pos];
		//console.log(this.memory);
	}
	AI.prototype.analysisMemory=function(){
		var UA=this._VanalysisMemory(this.userA);
		var UB=this._VanalysisMemory(this.userB);
		var point=UA;
		if(UB.status<UA.status || (UB.status==UA.status && UB.minRegIndex<=UA.minRegIndex)){
			point=UB;
		}
		return point;
	}
	//5-8 新的AI分析
	AI.prototype._VanalysisMemory = function(userFlag){
		var Umemory=this.memory[userFlag];
		var data=this.checkerboard.data;
		var aiLength=this.depth*2;
		var reg=this.createRegs(userFlag);
		//get min
		var minRegIndex=9999;
		for(var p in Umemory){
			for(var i=0;i<Umemory[p].length;i++){
				if(!Umemory[p][i].flag) continue;
				var pn=p.split('_');
				if(!this.isSetPiece(pn[0],pn[1])){
					this.memory[userFlag][p][i].flag=false;
					continue;
				}
				var linedata=Umemory[p][i].linedata;
				var key=[];
				var t_rstr=reg[Umemory[p][i].regIndex].toString();
				for(var j=0;j<aiLength;j++){
					//console.log("第"+i+"项:",fourPos[i][j].x,fourPos[i][j].y);
					if(typeof data[linedata[j].x]=='undefined' || typeof data[linedata[j].x][linedata[j].y]=='undefined') continue;
					var mflag=data[linedata[j].x][linedata[j].y].flag;
					key.push(mflag);
				}
				key=key.toString();
				var nextPointIndex=key.indexOf(t_rstr);
				if(nextPointIndex>-1){
					minRegIndex=Math.min(minRegIndex,Umemory[p][i].regIndex);
				}else{
					this.memory[userFlag][p][i].flag=false;
				}
			}	
		}
		if(minRegIndex==9999){
			return {nextPos:{x:0,y:0},status:minRegIndex,minRegIndex:minRegIndex};
		}
		//get min regs
		var pos=[];
		for (var p in Umemory) {
			for(var i=0;i<Umemory[p].length;i++){
				if(!Umemory[p][i].flag) continue;
				if(Umemory[p][i].regIndex==minRegIndex){
					pos.push(p);
				}
			}
		}
		//get min-min pos
		var mpos=[];
		for(var i=0;i<pos.length;i++){
			var p=Umemory[pos[i]];
			var segIndexs=[];
			for (var j = 0; j < p.length; j++) {
				segIndexs.push(p[j].regIndex);
			}
			segIndexs.sort();
			mpos.push(typeof segIndexs[1]=='undefined'?0:segIndexs[1]);
		}
		var max=9999,index=0;
		for(var i=0;i<mpos.length;i++){
			if(mpos[i]!=0 && max>mpos[i]){
				index=i;
				max=mpos[i];
			}
		}
		var nextPos=pos[index].split('_');
		console.log(userFlag,minRegIndex,max,pos[index]);
		return {nextPos:{x:parseInt(nextPos[0]),y:parseInt(nextPos[1])},status:minRegIndex,minRegIndex:max};
	}
	
	
	//
	AI.prototype.isSetPiece=function(x,y){
		var data=this.checkerboard.data;
		if(typeof data[x]!='undefined' && typeof data[x][y]!='undefined' && data[x][y].flag=='0'){
			return true;
		}
		return false;
	}
	
	//
	AI.prototype.createRegs=function(flag){
		var reg=[
			[flag,flag,flag,flag,flag],
			//1-5
			[0,flag,flag,flag,flag],
			[flag,0,flag,flag,flag],
			[flag,flag,0,flag,flag],
			[flag,flag,flag,0,flag],
			[flag,flag,flag,flag,0],
			//6-8
			[0,flag,0,flag,flag,0],
			[0,flag,flag,0,flag,0],
			[0,flag,flag,flag,0],
			//9-14
			[flag,flag,flag,0],
			[0,flag,flag,flag],
			[flag,0,flag,flag,0],
			[flag,flag,0,flag,0],
			[0,flag,0,flag,flag],
			[0,flag,flag,0,flag],
			//15-18
			[0,flag,0,flag,0],
			[0,flag,0,0,flag,0],
			[0,0,0,flag,flag,0],
			[0,flag,flag,0,0,0],
			//19-26
			[0,flag,flag,0],
			[flag,0,0,flag,0],
			[0,flag,0,0,flag],
			[flag,flag,0],
			[0,flag,flag],
			[0,flag,0,flag],
			[flag,0,flag,0],
			[flag,0,flag],
			//26-28
			[0,flag,0],
			[0,flag],
			[flag,0]
		];
		return reg;
	}
	//根据当前piece检查棋盘
	AI.prototype.checkVictory=function(){
		/*
		 * status 说明
		 * -1:游戏结束
		 * 0:和棋
		 * 1:正常
		 */
		 
		var data=this.checkerboard.data;
		var fourPos=this.fourPos;
		var piece=this.piece;
		var aiLength=this.depth*2;
		var flag=this.piece.flag;
		//var obj={status:9999,nextPos:{x:-1,y:0}};
		var reg=this.createRegs(flag);
		//var u_risk=9999;//定位正则
		for(var i=0;i<4;i++){
			var keyArr=[],key=[];
			for(var j=0;j<aiLength;j++){
				//console.log("第"+i+"项:",fourPos[i][j].x,fourPos[i][j].y);
				if(typeof data[fourPos[i][j].x]=='undefined' || typeof data[fourPos[i][j].x][fourPos[i][j].y]=='undefined') continue;
				var mflag=data[fourPos[i][j].x][fourPos[i][j].y].flag;
				key.push(mflag);
				keyArr.push({
					x: fourPos[i][j].x,
					y: fourPos[i][j].y,
					flag: mflag
				});
			}
			var key=key.toString();
			
			
				for(var ri=0;ri<reg.length;ri++){
					var t_rstr=reg[ri].toString();
					//var t_reg=new RegExp(t_rstr,'ig');
					//if(t_reg.test(key)){
						var nextPointIndex=key.indexOf(t_rstr);
						if (nextPointIndex > -1) {
							if(ri==0){
								return true;
							}
							nextPointIndex=nextPointIndex/2;
							for (var pi = nextPointIndex; pi < nextPointIndex+reg[ri].length; pi++) {
								
								if (keyArr[pi].flag == 0) {
									if ((ri == 6 || ri == 7) && nextPointIndex>pi) {
										this.addMemory({x:keyArr[pi].x,y:keyArr[pi].y},{regIndex:ri,linedata:fourPos[i],flag:true},piece.flag);
									}else{
										var mri=(ri>=15 && ri<=18)?15:ri;
										this.addMemory({x:keyArr[pi].x,y:keyArr[pi].y},{regIndex:mri,linedata:fourPos[i],flag:true},piece.flag);	
									}
									
								}
							}
							break;
						}
					//}
				}
		}
		return false;
	}
	
	//棋盘
	var Checkerboard=function(width, height){
		this.width=width;
		this.height=height;
		this.init();
	}
	Checkerboard.prototype.init=function(){
		this.data=[];
		for(var i=0;i<this.width;i++){
			var _a=[];
			for (var j = 0; j < this.height; j++) {
				_a[j]={flag:0};
			}
			this.data[i]=_a;
		}
		
	}
	Checkerboard.prototype.setGUI=function(guiWidth,guiHeight){
		var w=guiWidth/this.width;
		var h=guiHeight/this.height;
		$('#Checkerboard').empty();
		for (var j = 0; j < this.height; j++) {
				var $tr=$('<tr></tr>');
				for (var i = 0; i < this.width; i++) {
					if(j==0){
						if(i==0){
							$('<td><div class="td_pos"><img src="150px-Cross2.svg.png" width="'+w+'" height="'+h+'"/><div class="pos_left">'+(j)+'</div><div class="pos_top">'+(i)+'</div></div></td>').appendTo($tr);
						}else{
							$('<td><div class="td_pos"><img src="150px-Cross2.svg.png" width="'+w+'" height="'+h+'"/><div class="pos_top">'+(i)+'</div></div></td>').appendTo($tr);
						}
					}else if(i==0){
						$('<td><div class="td_pos"><img src="150px-Cross2.svg.png" width="'+w+'" height="'+h+'"/><div class="pos_left">'+(j)+'</div></div></td>').appendTo($tr);
					}else{
						$('<td><div class="td_pos"><img src="150px-Cross2.svg.png" width="'+w+'" height="'+h+'"/></div></td>').appendTo($tr);
					}
					
				}
				$tr.appendTo('#Checkerboard');
		}
	}
	Checkerboard.prototype.appendPiece=function(piece){
		if(typeof this.data[piece.x]!='undefined' && typeof this.data[piece.x][piece.y]!='undefined' && this.data[piece.x][piece.y].flag==0){
			this.data[piece.x][piece.y]=piece;
			console.log("当前棋子:",this.data[piece.x][piece.y]);
			return true;
		} 
		return false;
	}
	//棋子
	var Piece=function(x,y,flag){
		this.x=x;
		this.y=y;
		this.flag=flag;
	}
	Piece.prototype.appendTo=function(checkerboard){
		if(typeof checkerboard.data[this.x][this.y]=='undefined') return false;
		checkerboard.data[this.x][this.y]={x:this.x,y:this.y,flag:this.flag};
		console.log("当前棋子:",checkerboard.data[this.x][this.y]);
		//return this.checkVictory(checkerboard.data);
	}
	Piece.prototype.checkVictory=function(checkerboard){
		var eightBase=AI.fixBoard(0).concat(AI.fixBoard(45));
		var eightPos=AI.makeEightPos(this,eightBase);
		var fourPos=AI.makeFourPos(eightPos);
		return AI.checkVictory(checkerboard,fourPos,this);
	}
	
	////////////
	var GUI_W=600,GUI_H=600;
	var qipan;
	var WuZiAI;
	var $oldimg;
	function regame(){
		qipan=new Checkerboard(20,20);
		qipan.setGUI(GUI_W,GUI_H);
		WuZiAI=new AI(qipan);
		eventWuzi();
	}
	function eventWuzi(){
		var $tr=$('tr');
		$('td').click(function(){
			var td=this;
			var x,y;
			for(var i=0;i<$tr.length;i++){
				x=$('td',$tr[i]).index(td);
				if(x>-1){
					y=i;
					break;
				}
			}
			if (x > -1) {
				//console.log("棋子位置:",x, y);
				var Hqizi=new Piece(x, y,WuZiAI.userA);
				if(!qipan.appendPiece(Hqizi)) return;
				$('img',td).attr('src','heizi.png');
				//Hqizi.appendTo(qipan);
				if(WuZiAI.check(Hqizi)){
					alert("游戏结束,黑子胜利");
					$('td').unbind('click');
					return;
				}
				/////////////////////////////////////////////////
				///////////////AI 计算下子位置          ////////////////
				/////////////////////////////////////////////////
				
				var Next=WuZiAI.analysisMemory();
				//console.log("Next",Next);
				if(Next.status==-1){
					alert("游戏结束,和棋");
					$('td').unbind('click');
					return;
				}
				
				var Bqizi=new Piece(Next.nextPos.x, Next.nextPos.y,WuZiAI.userB);
				
				if (!qipan.appendPiece(Bqizi)) {
					alert('AI 出错!!!');
					$('td').unbind('click');
					return;
				}
				var $newtr=$('tr:eq('+Next.nextPos.y+')');
				var $newtd=$('td:eq('+Next.nextPos.x+')',$newtr);
				$('img',$newtd).attr('src','nowzi.png');
				if($oldimg){
					$oldimg.attr('src','baizi.png');
				}
				$oldimg=$('img',$newtd);
				
				if(WuZiAI.check(Bqizi)){
					alert("游戏结束,白子胜利");
					$('td').unbind('click');
					return;
				}
				
				return;
			}
		});
	}
	$(function(){
		$('#Checkerboard').css({width:GUI_W+'px',height:GUI_H+'px'});
		qipan=new Checkerboard(20,20);
		qipan.setGUI(GUI_W,GUI_H);
		WuZiAI=new AI(qipan);
		eventWuzi();
	});
</script>
</head>
<body>
	<div class="aiinfo">
		<h1>AI 算法概述:</h1>
圆心位置设置为棋子位置,将圆分割为4等分,然后转动45度角在分割4等分,这样就得到8个点,这8个点正好就是棋子周围的8个点;<br>
将圆半径从1循环到5,这样将得到每8个方向上的5点<br>
然后将8方向对角合并后就得到4条线上的10+1点,这1点便是当前的棋子。<br>
然后将4条线的棋子转成串,用正则匹配权值。<br>
如合并后的串为 "0UUU0000000",正则为 /0UUU0/,计算出棋子需要下在第一位。<br> <br>
目前 AI 还有些幼稚,正在完善中。<br>
<ul>
	<li>目前对AI的下子点没有做全局的估算</li>
	<li></li>
	<li></li>
	<li>[欢迎交流]goto999@126.com</li>
</ul>
		<h1>AI 算法详细:</h1>
	</div>
	<table id="Checkerboard"  cellpadding="0" cellspacing="0"></table>
	<div class="aiinfo">
		<h1>AI 中的问题:</h1>
		<button onclick="regame();">重玩</button>
	</div>
</body>
</html>
Add New Content