• 多种模式的五子棋


    本次版本包含人机对战(机器先手、机器后手)、人人模式(默认)、提示功能等。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <style>
                *{
                    padding: 0;margin: 0;
                }
                html,body{width:100%;height: 100%;}
                div{
                    text-align: center;
                }
                div button{
                    line-height: 16px;
                    font-size: 16px;
                    padding: 5px 10px;
                    border-radius: 5px;
                    background: #e73480;
                    color: white;
                    border: none;
                }
                .canvas{
                    margin: 0 auto;
                }
            </style>
        </head>
        <body>
            <div class="canvas">
                <canvas id="gobang"></canvas>
            </div>
            
            <div>
                <button id="requestSupport">提示</button>
                <button id="offense">先手人机</button>
                <button id="defense">后手人机</button>
                <button id="regret">悔棋</button>
                <button id="giveup">认输</button>
                <button id="restart">再来一局</button>
                <button id="negotiate">求和</button>
            </div>
        </body>
        <script src="man-machine4.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var gobang = new Gobang("gobang");
            // requestSupport
            document.getElementById("offense").addEventListener("click",()=>{
                if(0 && gobang.canContinue){
                    alert("不可以中途开局,你可以先认输~~~");
                }else{
                    gobang.machineFirst();
                }
            },false);
            document.getElementById("defense").addEventListener("click",()=>{
                if(0 && gobang.canContinue){
                    alert("不可以中途开局,你可以先认输~~~");
                }else{
                    gobang.manFirst();
                }
            },false);
            document.getElementById("requestSupport").addEventListener("click",()=>{
                gobang.requestSupport && gobang.requestSupport();
            },false);
            document.getElementById("regret").addEventListener("click",()=>{
                gobang.regret();
            },false);
            document.getElementById("giveup").addEventListener("click",()=>{
                if(confirm("你确定认输吗?")){
                    gobang.giveUp();
                }
            },false);
            document.getElementById("restart").addEventListener("click",()=>{
                gobang.reStart();
            },false);
            document.getElementById("negotiate").addEventListener("click",()=>{
                if(confirm("你确定求和吗?")){
                    gobang.negotiate();
                }
            },false);
        </script>
    </html>
    // 五子棋
    
    class Gobang {
    	constructor(canvasId, rowCount = 16) {
    		this.canvasId = canvasId;
    		this.rowCount = rowCount;
    
    		this.resetData();
    	}
    
    	// 渲染页面
    	renderUi() {
    		//清除之前的画布
    		this.ctx.clearRect(0, 0, this.width, this.height);
    
    		// 重绘画布
    		this.drawChessBoard();
    		this.drawPieces();
    	}
    
    	// 重置数据,再来一局
    	resetData() {
    		var body = document.documentElement || document.body;
    		var minWidth = Math.min(body.clientWidth,body.clientHeight-50);
    
    		// 属性
    		this.pieces = []; // 棋子数组 二位数组[[],[]] 0——空  1——白  2——黑
    		this.colCount = this.rowCount; // 列数
    		this.cellWidth = minWidth / (this.rowCount); //每个格子的宽
    		this.width = this.rowCount * this.cellWidth; // 棋盘的宽
    		this.height = this.width; // 棋盘的高
    		this.R = this.cellWidth * 0.4; // 棋子半径
    		this.hisStatus = []; // 历史记录 history status
    		this.active = 2; // 默认黑棋先走
    		
    		this.manMachine = false; // true-人机模式	false-人人模式
    		this.machine = 2; // 机器人执棋 2-黑棋	1-白棋
    		
    		this.canvas = document.getElementById(this.canvasId); // canvas DOM
    		this.ctx = this.canvas.getContext("2d"); // canvas环境
    		this.victor = 0; // 胜利方
    		this.canContinue = true; // 是否可以继续下棋(产生赢家以后不可以)
    		this.myPositions = []; // 我方的推荐位置数组  		格式:{x:5,y:6,weight:8}
    		this.enemyPositions = []; // 敌方的推荐位置数组
    
    		this.init();
    	}
    
    	// 初始化数据
    	init() {
    		this.initCanvas();
    		this.initPiece();
    		this.renderUi();
    	}
    	
    	// 暂时给棋盘中间加一个黑棋
    	first(){
    		var center = Math.floor((this.rowCount+1)/2);
    		this.pieces[center][center] = this.active;
    		this.hisStatus[1] = this.deepClone(this.pieces);
    		this.exchange();
    	}
    
    	// 设置棋盘的宽高
    	initCanvas() {
    		this.canvas.width = this.width;
    		this.canvas.height = this.height;
    		
    		this.canvas.addEventListener("click",(e)=>{ // 小心this转移
    			var offset = this.canvas.getBoundingClientRect();
    			var x = Math.round((e.clientX - offset.left) / this.cellWidth);
    			var y = Math.round((e.clientY - offset.top) / this.cellWidth);
    			// console.log(x,y,"点击位置");
    			
    			// 走棋
    			this.goStep(x,y);
    		},false);
    	}
    	
    	// 高亮最近走的棋子
    	highLight(x,y,oneSide){
    		var anotherSide = oneSide == 1 ? 2 : 1;
    		var length = this.R*0.5;
    		this.ctx.beginPath();
    		this.ctx.moveTo(x * this.cellWidth - length, y * this.cellWidth);
    		this.ctx.lineTo(x * this.cellWidth + length, y * this.cellWidth);
    		this.ctx.moveTo(x * this.cellWidth, y * this.cellWidth - length);
    		this.ctx.lineTo(x * this.cellWidth, y * this.cellWidth + length);
    		this.ctx.strokeStyle = this.getColor(anotherSide);
    		
    		this.ctx.stroke();
    	}
    
    	// 初始化棋子
    	initPiece() {
    		var initPieces = [];
    		for(let i = 0; i <= this.rowCount; i++) { // 行
    			initPieces.push([]);
    			for(let j = 0; j <= this.colCount; j++) { // 列
    				if(i==0 || j==0 || i==this.rowCount || j==this.rowCount){
    					initPieces[i].push(-1); // 不可以走的位置-1  空0 白1  黑2
    				}else{
    					initPieces[i].push(0); // 空0 白1  黑2
    				}
    			}
    		}
    		this.pieces = this.deepClone(initPieces);
    		this.hisStatus[0] = this.deepClone(initPieces);
    		//this.first();
    	}
    	
    	// 获取某个棋子的颜色 	0——空  1——白  2——黑
    	getColor (num){
    		var res = "";
    		console.trace();
    		// console.log(num);
    		switch(num){
    			case 0:
    				res = "";
    				break;
    			case 2:
    				res = "black";
    				break;
    			case 1:
    				res = "white";
    				break;
    			case -1:
    				res = "yellow";
    				break;
    			default: 
    				res="red"; // 错误了
    		}
    		return res;
    	}
    
    	// 画棋盘
    	drawChessBoard() {
    		// 背景
    		this.ctx.beginPath();
    		this.ctx.rect(0, 0, this.width, this.height);
    		this.ctx.closePath();
    		this.ctx.fillStyle = "#0099CC";
    		this.ctx.fill();
    
    		// 画横线
    		this.ctx.beginPath();
    		for(let i = 0; i < this.rowCount; i++) {
    			this.ctx.moveTo(0, this.cellWidth * i);
    			this.ctx.lineTo(this.width, this.cellWidth * i);
    		}
    		this.ctx.strokeStyle = "#333";
    		this.ctx.stroke();
    
    		// 画纵线
    		this.ctx.beginPath();
    		for(let i = 0; i < this.colCount; i++) {
    			this.ctx.moveTo( this.cellWidth * i, 0);
    			this.ctx.lineTo( this.cellWidth * i, this.height);
    		}
    		this.ctx.strokeStyle = "#333";
    		this.ctx.stroke();
    	}
    
    	// 画一个棋子
    	drawDot(x, y, r, color) {
    		this.ctx.beginPath();
    		this.ctx.arc(x, y, r, 0, 2 * Math.PI);
    		this.ctx.closePath();
    
    		this.ctx.fillStyle = color;
    		this.ctx.fill();
    	}
    
    	// 画所有的棋子
    	drawPieces(x, y) {
    		//console.log(this.pieces)
    		for(var i = 0; i < this.pieces.length; i++) { // 边界线不让走棋
    			for(let j=0; j < this.pieces[i].length;j++){
    //				if(this.pieces[i][j] == 1 || this.pieces[i][j] == 2){
    				if(this.pieces[i][j] !== 0){
    					var x = i * this.cellWidth;
    					var y = j * this.cellWidth;
    //					var y = j * this.cellWidth - this.cellWidth/2;
    					this.drawDot(x,y,this.R,this.getColor(this.pieces[i][j]));
    				}
    			}
    		}
    	}
    	
    	// 
    	drawOnePiece(i,j){
    		var x = i * this.cellWidth;
    		var y = j * this.cellWidth;
    		this.drawDot(x,y,this.R,this.getColor(this.active));
    	}
    	
    	// 判断是否可以走这一步
    	canGo(x, y) {
    		if(this.canContinue === false){
    			alert("游戏已结束");
    			return false;
    		}
    		if(x==0 || y==0 || x==this.rowCount || y==this.rowCount){
    			alert("边界上不可以走棋哦");
    			return false;
    		}
    		if(this.pieces[x][y]==0){
    			return true;
    		}else {
    			return false;
    		}
    	}
    	
    	// 切换角色(换着走棋)
    	exchange(){
    		this.active = this.active == 1 ? 2 : 1;
    	}
    
    	manGoStep(x, y){
    		if(this.canGo(x,y)){
    			this.pieces[x][y] = this.active;//添加棋子
    			this.renderUi();
    			this.highLight(x,y,this.active);
    			this.hisStatus.push(this.deepClone(this.pieces));//历史记录(悔棋复盘功能使用)
    			this.getVictor();//这里有个坑,棋子还没有画上去,已经把输赢判断了????
    			this.exchange();
    			if(this.manMachine == true){
    				this.requestSupport();
    			}
    		}else{
    			// alert("这个位置已经被占领了,换个位置走吧");
    		}
    	}
    
    	// 走一步棋
    	goStep(x,y) {
    		// 判断这一步是否可以走
    		if(this.manMachine == true){
    			// 人机模式
    			if(this.machine == this.active){ // 轮到机器人走
    				this.requestSupport();
    			}else{ // 轮到人走
    				this.manGoStep(x, y);
    			}
    		}else{
    			// 人人模式
    			this.manGoStep(x, y);
    		}	
    	}
    	
    	// 任何时候点击提示后,给出一个推荐位置
    	requestSupport(){ // 请求支援
    		this.helpRecommend(this.active);
    		// console.log(this.myPositions,this.enemyPositions)
    		var p = this.bestPosition();
    		console.log(p);
    		if(Object.keys(p).length != 0){
    			
    		}else{ // 第一次没有棋子,推荐的位置为空,默认推荐到中间
    			var x = parseInt(this.rowCount / 2);
    			var y = parseInt(this.rowCount / 2);
    			if(this.canGo(x, y)){
    				p.x = x;
    				p.y = y;
    			}else{
    				alert("没有有效位置了,自己随便走吧");
    			}
    		}
    		this.pieces[p.x][p.y] = this.active;
    		this.renderUi();
    		this.highLight(p.x,p.y,this.active);
    		this.getVictor();
    		this.exchange();
    	}
    	
    	// 悔棋
    	regret() {
    		if(this.hisStatus.length<=1){
    			console.log("当前不可以悔棋了");
    			return;
    		}
    		this.canContinue = true;
    		this.victor = 0;
    		
    		this.hisStatus.pop();
    		this.hisStatus.pop();
    		this.pieces = this.deepClone(this.hisStatus[this.hisStatus.length-1]);
    		// this.exchange();
    		this.renderUi();
    	}
    	
    	// 重新开始
    	reStart(){
    		if(!this.victor){
    			alert("还没有结束,不能重新开始");
    		}else{
    			this.resetData();
    		}
    	}
    	
    	// 求和
    	negotiate(){
    		alert("和棋");
    		this.resetData();
    	}
    	
    	// 认输
    	giveUp(){
    		this.victor = this.active == 1 ? 2 : 1;
    		this.getWinner();
    		setTimeout(()=>{
    			this.resetData();
    		},60);
    	}
    	
    	// 机器人先走
    	machineFirst(){
    		this.resetData();
    		this.manMachine = true;
    		this.machine = 2;
    		this.requestSupport();
    	}
    	
    	// 机器人后走
    	manFirst(){
    		this.resetData();
    		this.manMachine = true;
    		this.machine = 1;
    	}
    	
    	// 棋型判断 活三 死三等	  都有对称情况
    	defineType (x,y){
    		// 类型  权重 棋型
    		// 活四  8 ?AAAA? 
    		// 死四  7 BAAAA?——?AAAAB  AA?AA
    		// 活三  6 ??AAA?——?AAA??  ?A?AA?——?AA?A?
    		// 死三  5 BAAA??——??AAAB  BAA?A?——?A?AAB  BA?AA?——?AA?AB
    		// 活二  4 ?AA???——???AA?  
    		// 死二  3 BAA???  AA????
    		// 活一  2 
    		// 死一  1
    	}
    	
    	
    	helpRecommend(oneSide){
    		var enemySide = oneSide == 1 ? 2 : 1;
    		this.myPositions = [];
    		this.enemyPositions = [];
    		var aimArr,standpoint;
    		
    		for(let i=1;i<this.rowCount;i++){
    			
    			for(let j=1;j<this.rowCount;j++){
    				
    //				 var arr = ["r","rd","d","ld","l","lt","t","rt"];
    				var arr = ["r","rd","d","ld"];
    				// 权重相关变量 forward  backward   center  double  null
    				
    				var n2f1 = 0.2, // 两头空时 前面第一个空位置的权重
    					n2f2 = 0.2, // 两头空时 前面第二个空位置的权重
    					n2b1 = n2f1,
    					n2b2 = n2f2,
    					n1f1 = -0.8, // 一头空另一头是敌方或边界时  前面第一个空位置的权重
    					n1f2 = -0.8,
    					n1b1 = n1f1,
    					n1b2 = n1f2,
    					dn2c = 0.2, // 有两个片段时   两端都是空的时   中间位置的权重
    					dn2b1 = 0.2,// 有两个片段时   两端都是空的时   后方第一个位置的权重
    					dn2f1 = dn2b1,
    					dn1c = -0.5,
    					dn1b1 = -0.5,
    					dn1f1 = dn1b1;
    					
    				
    				if(this.pieces[i][j]==oneSide){ // 我方
    					aimArr = this.myPositions;
    					standpoint = oneSide;
    				}else if(this.pieces[i][j]==enemySide){ // 敌方
    					aimArr = this.enemyPositions;
    					standpoint = enemySide;
    				}else{
    					continue;
    				}
    				
    				console.table([{i:i,j:j,qizi:this.pieces[i][j],standpoint:standpoint}])
    				
    				
    				
    				for(var d =0;d<arr.length;d++){
    					var count = 0;
    					count = this.directionCount(arr[d],standpoint,i,j);
    					var nd = this.nd(arr[d]);
    					var h = nd.h;
    					var v = nd.v;
    					
    					// 赢棋的单独写
    					if(count == 4){
    						if(this.pieces[i-1*h] && this.pieces[i-1*h][j-1*v] === 0){ // 前1空
    							this.sumWeight(aimArr,i-1*h,j-1*v,10**5);
    						}else{
    							if(this.pieces[i+count*h] && this.pieces[i+count*h][j+count*v] === 0){ // 末1空
    								this.sumWeight(aimArr,i+count*h,j+count*v,10**5);
    							}
    						}
    						continue;
    					}else{
    						
    					}
    					
    					// 某个方向的末端的推荐权重  (权重暂时认为后方第一个位置和第二位位置一样) 两头空的+0.2  一端空的+0  两端都死的考虑能否凑5个子
    					if(this.pieces[i-1*h] && this.pieces[i-1*h][j-1*v] === 0){ // 前1空
    						if(this.pieces[i+count*h] && this.pieces[i+count*h][j+count*v] === 0){ // 末1空
    							if(this.pieces[i+(count+1)*h] && this.pieces[i+(count+1)*h][j+(count+1)*v] === 0){ //末2空
    								if(count>=3){
    									this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+n2b1+0.3));
    									this.sumWeight(aimArr,i+(count+1)*h,j+(count+1)*v,10**(count+n2b2));
    								}else{
    									this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+n2b1));
    									this.sumWeight(aimArr,i+(count+1)*h,j+(count+1)*v,10**(count+n2b2));
    								}
    							}else if(this.pieces[i+(count+1)*h] && this.pieces[i+(count+1)*h][j+(count+1)*v] === standpoint){ // 末2己
    								let count2 = this.directionCount(arr[d],standpoint,i+(count+1)*h,j+(count+1)*v);
    								if(count+count2 >= 4){ // 可以赢的特殊算
    									this.sumWeight(aimArr,i+count*h,j+count*v,10**5);
    								}else{
    									if(this.pieces[i+(count+1+count2)*h] && this.pieces[i+(count+1+count2)*h][j+(count+1+count2)*v] === 0){
    										this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+count2+dn2c));
    										this.sumWeight(aimArr,i+(count+1+count2)*h,j+(count+1+count2)*v,10**(count+count2+dn2b1));
    									}else {
    										this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+count2+dn1c));
    									}
    								}
    									
    							}else { //末2敌或边界  
    								this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+n1b1));
    							}
    						}else { // 末1敌或边界   末1不可能是己方的
    							// 末端没有推荐的位置
    						}
    					}else if(this.pieces[i-1*h] && this.pieces[i-1*h][j-1*v] === standpoint){ // 前1己  这里已经计算过了,跳过逻辑
    						continue;
    					}else { // 前1 敌方或边界
    						if(this.pieces[i+count*h] && this.pieces[i+count*h][j+count*v] === 0){ // 末1空
    							if(this.pieces[i+(count+1)*h] && this.pieces[i+(count+1)*h][j+(count+1)*v] === 0){ //末2空
    								this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+n1b1));
    								this.sumWeight(aimArr,i+(count+1)*h,j+(count+1)*v,10**(count+n1b2));
    							}else if(this.pieces[i+(count+1)*h] && this.pieces[i+(count+1)*h][j+(count+1)*v] === standpoint){ // 末2己
    //									this.sumWeight(this.myPositions,i+count*h,j+count*v,10**(count+0.1));
    								let count2 = this.directionCount(arr[d],standpoint,i+(count+1)*h,j+(count+1)*v);
    								if(count+count2 >= 4){
    									this.sumWeight(aimArr,i+count*h,j+count*v,10**5);
    								}else{
    									if(this.pieces[i+(count+1+count2)*h] && this.pieces[i+(count+1+count2)*h][j+(count+1+count2)*v] === 0){
    										this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+count2+dn1c));
    										this.sumWeight(aimArr,i+(count+1+count2)*h,j+(count+1+count2)*v,10**(count+count2+dn1b1));
    									}else {// 两端是死的 中间要么是5要么就没意义
    										if(count+1+count2 == 5){
    											this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+count2+1));
    										}else{
    											this.sumWeight(aimArr,i+count*h,j+count*v,0);
    											//console.log("中间凑不够5个,中间权重是0");
    										}
    									}
    								}
    									
    							}else { //末2敌或边界
    								if(count==4){ // 只有四颗子的时候这个位置才有意义
    									this.sumWeight(aimArr,i+count*h,j+count*v,10**(count+1));
    								}
    							}
    						}else { // 末1敌或边界   末1不可能是己方的
    							// 走不了了
    						}
    					}
    					
    					// 某个方向的前端的推荐权重
    					if(this.pieces[i+count*h] && this.pieces[i+count*h][j+count*v] === 0){ // 后1空
    						if(this.pieces[i-1*h] && this.pieces[i-1*h][j-1*v] === 0){ // 前1空
    							if(this.pieces[i-2*h] && this.pieces[i-2*h][j-2*v] === 0){ //前2空
    								if(count>=3){
    									this.sumWeight(aimArr,i-1*h,j-1*v,10**(count+n2f1+0.3));
    									this.sumWeight(aimArr,i-2*h,j-2*v,10**(count+n2f2));
    								}else{
    									this.sumWeight(aimArr,i-1*h,j-1*v,10**(count+n2f1));
    									this.sumWeight(aimArr,i-2*h,j-2*v,10**(count+n2f2));
    								}
    							}else if(this.pieces[i-2*h] && this.pieces[i-2*h][j-2*v] === standpoint){ // 前2己
    //									this.sumWeight(this.myPositions,i-1*h,j-1*v,10**(count+0.3));
    								let count2 = this.directionCount(this.reverseDirection(arr[d]),standpoint,i-2*h,j-2*v);
    								if(count+count2 >= 4){
    									this.sumWeight(aimArr,i-1*h,j-1*v,10**5);
    								}else{
    									if(this.pieces[i-(1+count2)*h] && this.pieces[i-(1+count2)*h][j-(1+count2)*v] === 0){
    										this.sumWeight(aimArr,i-1*h,j-1*v,10**(count+count2+dn2c));
    										this.sumWeight(aimArr,i-(1+count2)*h,j-(1+count2)*v,10**(count+count2+dn2f1));
    									}else {
    										this.sumWeight(aimArr,i-1*h,j-1*v,10**(count+count2+dn1c));
    										this.sumWeight(aimArr,i-(1+count2)*h,j-(1+count2)*v,10**(count+count2+dn1f1));
    									}
    								}
    									
    							}else { //前2敌或边界
    								this.sumWeight(aimArr,i-1*h,j-1*v,10**(count+n1f1));
    							}
    						}else { // 前1敌或边界   前1不可能是己方的
    							// 前端没有推荐的位置
    						}
    					}else if(this.pieces[i+count*h] && this.pieces[i+count*h][j+count*v] === standpoint){ // 后1己  这里已经计算过了,跳过逻辑
    						continue;
    					}else { // 后1 敌方或边界
    						if(this.pieces[i-1*h] && this.pieces[i-1*h][j-1*v] === 0){ // 前1空
    							if(this.pieces[i-2*h] && this.pieces[i-2*h][j-2*v] === 0){ //前2空
    								this.sumWeight(aimArr,i-1*h,j-1*v,10**(count+n1f1));
    								this.sumWeight(aimArr,i-2*h,j-2*v,10**(count+n1f2));
    							}else if(this.pieces[i-2*h] && this.pieces[i-2*h][j-2*v] === standpoint){ // 前2己
    								// this.sumWeight(this.myPositions,i-1*h,j-1*v,10**(count+0.1));
    								let count2 = this.directionCount(this.reverseDirection(arr[d]),standpoint,i-2*h,j-2*v);
    								if(count+count2 >= 4){
    									this.sumWeight(aimArr,i-1*h,j-1*v,10**5);
    								}else{
    									if(this.pieces[i-(1+count2)*h] && this.pieces[i-(1+count2)*h][j-(1+count2)*v] === 0){
    										this.sumWeight(aimArr,i-1*h,j-1*v,10**(count+count2+dn1c));
    										this.sumWeight(aimArr,i-(1+count2)*h,j-(1+count2)*v,10**(count+count2+dn1f1));
    									}else {
    										if(count+1+count2 == 5){
    											this.sumWeight(aimArr,i-1*h,j-1*v,10**(count+count2+1));
    										}else{
    											this.sumWeight(aimArr,i-1*h,j-1*v,0);
    											//console.log("中间凑不够5个,中间权重是0");
    										}
    									}
    								}
    							}else { //前2敌或边界
    								if(count==4){ // 只有四颗子的时候这个位置才有意义
    									this.sumWeight(aimArr,i-2*h,j-2*v,10**(count+1));
    								}
    							}
    						}else { // 前1敌或边界  前1不可能是己方的
    							// 前后都是敌,推荐个锤子
    						}
    					}
    				}
    				
    			}
    		}
    	}
    	
    	
    	reverseDirection(direction){
    		var rd = "";
    		switch(direction){
    			case "r":
    				rd = "l";break;
    			case "rd":
    				rd = "lt";break;
    			case "d":
    				rd = "t";break;
    			case "ld":
    				rd = "rt";break;
    			case "l":
    				rd = "r";break;
    			case "lt":
    				rd = "rd";break;
    			case "t":
    				rd = "d";break;
    			case "rt":
    				rd = "ld";break;
    			default: console.error("输入方向不对,无法反转"); 	
    		}
    		return rd;
    	}
    	
    	// 方向数字化numberDirection r(1,0) rd(1,1) ld(-1,1)
    	nd(direction){
    		var res = {h:0,v:0}; // h horizontal v vertical
    		switch(direction){
    			case "r":
    				res.h = 1;
    				res.v = 0;
    				break;
    			case "rd":
    				res.h = 1;
    				res.v = 1;
    				break;
    			case "d":
    				res.h = 0;
    				res.v = 1;
    				break;
    			case "ld":
    				res.h = -1;
    				res.v = 1;
    				break;
    			case "l":
    				res.h = -1;
    				res.v = 0;
    				break;
    			case "lt":
    				res.h = -1;
    				res.v = -1;
    				break;
    			case "t":
    				res.h = 0;
    				res.v = -1;
    				break;
    			case "rt":
    				res.h = 1;
    				res.v = -1;
    				break;
    			default: console.error("方向输入有误");
    		}
    		return res;
    	}
    	
    	// 合并同一个位置的权重
    	sumWeight(arr,x,y,weight){
    		weight = parseInt(weight); // 这里取一下整,小数看着不爽
    		var index = -1;
    		for(let i=0,len=arr.length;i<len;i++){
    			if(arr[i].x==x && arr[i].y==y){
    				index = i;
    				break;
    			}
    		}
    		if(index!=-1){ // 如果已存在则权重相加
    			arr[index].weight += weight;
    		}else{ // 如果不存在则添加一条
    			arr.push({x,y,weight});
    		}
    	}
    	
    	// 从推荐位置中找出最佳位置  权重最大的位置
    	bestPosition (){
    		var myMax=0,myP={},myArr=[];
    		for(let i=0,len=this.myPositions.length;i<len;i++){
    			if(this.myPositions[i].weight>myMax){
    				myMax = this.myPositions[i].weight;
    				myP.x = this.myPositions[i].x;
    				myP.y = this.myPositions[i].y;
    			}
    		}
    		var enemyMax = 0, enemyP = {}, enemyArr = [];
    		for(let i=0,len=this.enemyPositions.length;i<len;i++){
    			if(this.enemyPositions[i].weight>enemyMax){
    				enemyMax = this.enemyPositions[i].weight;
    				enemyP.x = this.enemyPositions[i].x;
    				enemyP.y = this.enemyPositions[i].y;
    			}
    		}
    //		console.log(this.myPositions,this.ememyPositions);
    		//console.log("敌方权重最大:"+enemyMax,"我方权重最大:"+myMax);
    		
    		for(let i=0,len=this.myPositions.length;i<len;i++){
    			if(this.myPositions[i].weight==myMax){
    				myArr.push(this.deepClone(this.myPositions[i]));
    			}
    		}
    		for(let i=0,len=this.enemyPositions.length;i<len;i++){
    			if(this.enemyPositions[i].weight==enemyMax){
    				enemyArr.push(this.deepClone(this.enemyPositions[i]));
    			}
    		}
    		console.log(myArr,enemyArr,"敌方权重最大:"+enemyMax,"我方权重最大:"+myMax)
    		if(enemyMax>myMax){
    			// 敌方权重最大的地方(有相同位置时,谋求自己的大权重位置)
    			var myMaxW = 0; // 我方在敌方最有位置处的最佳权重
    			var recommedP = enemyP;
    			for(let i=0, len=enemyArr.length;i<len;i++){
    				for(let j=0,len1=this.myPositions.length;j<len1;j++){
    					if(this.myPositions[j].x==enemyArr[i].x && this.myPositions[j].y==enemyArr[i].y){
    						if(this.myPositions[j].weight>myMaxW){
    							myMaxW = this.myPositions[j].weight;
    							recommedP.x = this.myPositions[j].x;
    							recommedP.y = this.myPositions[j].y;
    						}
    					}
    				}
    			}
    			return recommedP;
    		}else {
    			// 我方权重最大的地方(有相同位置时,占据敌方的相对大权重位置)
    			var enemyMaxW = 0; // 我方在敌方最有位置处的最佳权重
    			var recommedP = myP;
    			for(let i=0, len=myArr.length;i<len;i++){
    				for(let j=0,len1=this.enemyPositions.length;j<len1;j++){
    					if(this.enemyPositions[j].x==myArr[i].x && this.enemyPositions[j].y==myArr[i].y){
    						if(this.enemyPositions[j].weight>enemyMaxW){
    							enemyMaxW = this.enemyPositions[j].weight;
    							recommedP.x = this.enemyPositions[j].x;
    							recommedP.y = this.enemyPositions[j].y;
    						}
    					}
    				}
    			}
    			return recommedP;
    		}
    	}
    	
    	// 获取赢家
    	getWinner(){
    		switch(this.victor){
    			case 0:
    				// console.log("还没产生赢家");
    				break;
    			case 1: 
    				setTimeout(()=>{
    					alert("白棋赢");
    					this.canContinue = false;
    				},30);
    				break;
    			case 2:
    				setTimeout(()=>{
    					alert("黑棋赢");
    					this.canContinue = false;
    				},30);
    				break;
    			default:;
    		}
    	}
    
    	// 判断输赢
    	getVictor() { //1.找到一个当前棋子,2.判断它的右、右下、下、左下四个方向是否连成5个棋子
    		var dArr = ["r","rd","d","ld"];
    		for(var i=1;i<this.pieces.length;i++){
    			for(var j=1;j<this.pieces[i].length;j++){
    				if(this.pieces[i][j] == this.active){
    					for(let k =0;k<dArr.length;k++){
    						if(this.directionCount(dArr[k],this.active,i,j) == 5){// 右r 下d 左l 上t 
    							this.victor = this.active;
    							this.getWinner();
    							return;
    						}
    					}
    				}
    			}
    		}
    	}
    	
    	// 各个方向连珠数量判断
    	directionCount(direction,oneSide,i,j){
    		var count = 0;
    		var nd = this.nd(direction);
    		if(this.pieces[i][j] == oneSide){
    			count = 1;
    			for(let k=1;k<5;k++){
    				if(this.pieces[i+k*nd.h] && this.pieces[i+k*nd.h][j+k*nd.v] === oneSide){
    					count++;
    					continue;
    				}else {
    					break;
    				}
    			}
    		}
    		return count;
    	}
    	
    	
    	
    	// 深拷贝
    	deepClone(values) {
    		var copy;
    
    		// Handle the 3 simple types, and null or undefined
    		if(null == values || "object" != typeof values) return values;
    
    		// Handle Date
    		if(values instanceof Date) {
    			copy = new Date();
    			copy.setTime(values.getTime());
    			return copy;
    		}
    
    		// Handle Array
    		if(values instanceof Array) {
    			copy = [];
    			for(var i = 0, len = values.length; i < len; i++) {
    				copy[i] = this.deepClone(values[i]);
    			}
    			return copy;
    		}
    
    		// Handle Object
    		if(values instanceof Object) {
    			copy = {};
    			for(var attr in values) {
    				if(values.hasOwnProperty(attr)) copy[attr] = this.deepClone(values[attr]);
    			}
    			return copy;
    		}
    
    		throw new Error("Unable to copy values! Its type isn't supported.");
    	}
    }
    

      

  • 相关阅读:
    《Windows程序设计》中未归类的API
    C++编程技巧亮点集结
    详解python实现FPTREE进行关联规则挖掘(带有FP树显示功能)附源代码下载(5)
    python源码剖析 读书笔记
    python操作时间的几个重要函数总结 import time!
    判断关联规则是否可靠提升度 lift,KULC,IR
    详解python实现FPTREE进行关联规则挖掘(带有FP树显示功能)附源代码下载(3)
    python 使用装饰器模式 保证带有默认值的参数不被修改默认值
    python open文件 读写模式说明
    详解python实现FPTREE进行关联规则挖掘(带有FP树显示功能)附源代码下载(4)
  • 原文地址:https://www.cnblogs.com/zhaodesheng/p/10256265.html
Copyright © 2020-2023  润新知