五子棋2 canvas绘制棋盘 -HTML JS

20 篇文章 0 订阅
20 篇文章 1 订阅

大家好:

经过上一版的代码,又优化了一版,原因是,上一版的图片,在手机上不识别,于是我用canvas 画板,绘制了棋盘。调整了画布的大小,适用于手机。

代码展示:

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>手机-五子棋</title>
	<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
	<script type="text/javascript" src="../js/jquery-1.7.2.js"></script>
    <!-- css -->
    <style type="text/css">
    canvas{
		 display: block;
		 background-color:burlywood;
		 box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #B9B9B9;
		}
	.restart{
	    text-align: center;
	}
	.restart>span{
	    display: inline-block;
	    padding: 10px 20px;
	    color: #fff;
	    background-color: #45c01a;
	    border-radius: 5px;
	}
    </style>
    <!-- css ends -->    
    <!-- script -->
<script type="text/javascript">
	//页面加载
$(document).ready(function(){
	//画棋盘
    drawChessboard();
    
    /* canvas绑定点击事件 实现点击落子 */
	chess.onclick = function(e) {
	 /* 如果棋局结束 点击不再产生效果 */
	  if(over){return;}
	 /* 如果没有轮到黑方行棋 点击不触发事件 (如需双人对战,则取消该判断与下方AI行棋方法) */
	 if (!me) {return;}
	 
	 var x = e.offsetX; //点击位置横坐标
	 var y = e.offsetY; //点击位置纵坐标
	 var i = Math.floor(x / 20); //对应x坐标到棋盘所在交叉点
	 var j = Math.floor(y / 20); //对应y坐标到棋盘所在交叉点
	 /* 位置为空 可以落子 */
	 if (chessBoard[i][j] == 0) {
	  /* 落子 */
	  oneStep(i, j, me);
	
	  if (me) {
	   chessBoard[i][j] = 1; //黑方落子
	  } else {
	   chessBoard[i][j] = 2; //白方落子 -- 人机对战时 该行不会执行
	  }
	  /* 轮流落子 */
	  me = !me;
	
	  /* 落子完成之后 遍历所有赢法 */
	  for (var k = 0; k < count; k++) {
	   /* 包含落子点的赢法的统计数组 + 1 */
	   if(wins[i][j][k]){
	    BlackWin[k]++; //黑棋在第k种赢法中统计数字 + 1
	    WhiteWin[k] = 6; //同时白棋不可能以第k种赢法胜利
	    /* 胜利判断 */
	    if (BlackWin[k] == 5) {
	     window.alert("恭喜你,获得了胜利!");
	     over = true; //棋局结束
	    }
	   }
	  }
	
	  /* 如果棋局未结束 计算机AI自动执白行棋 */
	  if (!over) {
	   computerAI();
	  }
	 }
	}
	
	//点击‘重新开始’按钮
	$("#restart").click(function(){
	    window.location.reload();
	});
});
//画棋盘
function drawChessboard(){
	/***** UI设计 -- 棋盘绘制 & 棋子绘制 & 落子动作 *****/
	//获取Canvas面板 
	var chess = document.getElementById("chess");
	//2D面板-画笔
	var context = chess.getContext("2d");
	//绘制棋盘
	 //线条颜色 
	context.strokeStyle = "black";
	 for (var i = 0; i < 15; i++) {
	  //横线 
	  context.moveTo(15 + i * 20, 15);
	  context.lineTo(15 + i * 20, 295);
	  context.stroke();
	  //纵线 
	  context.moveTo(15, 15 + i * 20);
	  context.lineTo(295, 15 + i * 20);
	  context.stroke();
	 }
	//绘制棋盘上的5个标志点
	context.beginPath();//开始绘制新路径
    //arc(x, y, radius, startAngle, endAngle, counterclockwise):
    //以(x,y)为圆心绘制一条弧线,弧线半径为radius,起始和结束角度(用弧度表示)分别为startAngle 和endAngle。最后一个参数表示startAngle 和endAngle 是否按逆时针方向计算,值为false表示按顺时针方向计算。
    
    var number = 4;//圆半径
    //中心点
    context.arc(155,155,number,0,2*Math.PI);//参数1:左右移动;参数2:上下移动;参数3:大小;参数4:图形显示百分比
    //左上点
    context.arc(75,75,number,0,2*Math.PI);
    //右下点
    context.arc(235,235,number,0,2*Math.PI);
    context.closePath();
    context.fillStyle = 'red';
    context.fill();
    
    context.beginPath();//开始绘制新路径
    //左下
    context.arc(75,235,number,0,2*Math.PI);
    //右上
    context.arc(235,75,number,0,2*Math.PI);
    context.closePath();
    context.fillStyle = 'red';
    context.fill();
}
	
/* 走棋 */
	// param - i : 棋子落点第几行 
	// param - j : 棋子落点第几列 
	// param - me : 是否黑棋 
function oneStep(i, j, me) {
	 /* 画圆(棋子) */
	//获取Canvas面板 
	var chess = document.getElementById("chess");
	//2D面板-画笔
	var context = chess.getContext("2d");
	 context.beginPath();
	 context.arc(15 + i * 20, 15 + j * 20, 9, 0, 2 * Math.PI); //圆心x  圆心y  半径  弧度(起)  弧度(止)
	 context.closePath();
	 //context.stroke();//描边
	 //context.fill();//填充
	 
	/* 棋子颜色渐变 */
	 var gradient = context.createRadialGradient(15 + i * 20 + 2, 15 + j * 20 - 2, 9, 15 + i * 20 + 2, 15 + j * 20 - 2, 0); //外圆圆心坐标 半径, 内圆圆心坐标半径
	 if (me) {
	  //黑棋颜色
	  gradient.addColorStop(0, "#0A0A0A"); //外圆颜色 0代表百分比
	  gradient.addColorStop(1, "#636766"); //内圆颜色 1代表百分比
	  } else {
	  //白棋颜色
	  gradient.addColorStop(0, "#D1D1D1");
	  gradient.addColorStop(1, "#F9F9F9");
	 }
	 context.fillStyle = gradient;
	 context.fill();
}

 /* 定义全局变量 me 代表黑白棋 */
	var me = true; //默认黑棋先行
	/* 定义全局变量 over 代表棋局是否结束 */
	var over = false;
	/* 定义全局二维数组并初始化 存储每个落子点的落子情况 */
	var chessBoard = [];
	for (var i = 0; i < 15; i++) {
		 chessBoard[i] = [];
		 for (var j = 0; j < 15; j++) {
		  chessBoard[i][j] = 0; // 0 未落子;1 黑子;2 白子
		 }
	}
	/* 定义全局变量 count 存储赢法ID */
	var count = 0;
	
	/* 定义全局三维数组 存储所有的赢法 并初始化 */
	var wins = [];
	for (var i = 0; i < 15; i++) {
	 wins[i] = [];
	 for (var j = 0; j < 15; j++) {
	  wins[i][j] = [];
	 }
	}
	
	/* 遍历所有赢法 填充赢法数组 */
	/* 横向五子连线的情况 */
	for (var i = 0; i < 15; i++) {
	 for (var j = 0; j < 11; j++) {
	  for (var k = 0; k < 5; k++) {
	   wins[i][j + k][count] = true;
	  }
	  count++;
	 }
	}
	
	/* 纵向五子连线的情况 */
	for (var i = 0; i < 15; i++) {
	 for (var j = 0; j < 11; j++) {
	  for (var k = 0; k < 5; k++) {
	   wins[j + k][i][count] = true;
	  }
	  count++;
	 }
	}
	/* 正斜向五子连线的情况 */
	for (var i = 0; i < 11; i++) {
	 for (var j = 0; j < 11; j++) {
	  for (var k = 0; k < 5; k++) {
	   wins[i + k][j + k][count] = true;
	  }
	  count++;
	 }
	}
	/* 反斜向五子连线的情况 */
	for (var i = 0; i < 11; i++) {
	 for (var j = 14; j > 3; j--) {
	  for (var k = 0; k < 5; k++) {
	   wins[i + k][j - k][count] = true;
	  }
	  count++;
	 }
	}
	//console.log(count); //572 可知 15 * 15 的棋盘上 五子棋共有 572 种赢法
	
	/* 定义全局一维数组 统计某种赢法下黑白棋子的状态 并初始化 */
	var BlackWin = [];
	var WhiteWin = [];
	for (var i = 0; i < count; i++) {
	 BlackWin[i] = 0; // 0:未落子  1:落下1子 …… 5:胜利  6:异常 - 对方已经落子(此赢法为不可能)
	 WhiteWin[i] = 0; // 换句话说,当BlackWin和WhiteWin数组的所有值都为 6 时, 为和棋
	}



/***** AI算法基本思路与实现 *****/
	/* 1、计算机执白后行 */
	/* 2、计算目标:阻止黑棋五子连线 && 试图白棋五子连线 */
	/* 3、记录棋盘中可能出现的所有赢法。 三维数组(棋子x, 棋子y, 赢法ID) */
	/* 4、赢法统计数组。 对每一种赢法的当前落子情况统计 */
	/* 5、胜负判定 */
	/* 6、计算机落子优先系数 */
	/* 7、计算机执白后行,同情况下白棋优先级需要高于黑棋。 即黑白棋同时4子连线时,需优先连接白棋第5子而非拦截黑棋 */
	/* 8、得分累加来判定某一点落子的价值大小*/
	/* 9、获取落子价值得分最高的点 */
	/* 10、落子的价值分相同时, 优先级顺序的选择:高 --> 低   行白+拦黑  >  行白  >  拦黑+行白  >  拦黑 */
	
	/* AI算法实现 */
	var computerAI = function(){
	
	 /* 定义变量 保存落子价值得分最高的分数和点坐标 */
	 var max = 0;
	 var u = 0;
	 var v = 0;
	
	 /* 定义两个一维数组 存储当前黑棋和白棋的落子评分 并初始化*/
	 var BlackScore = [];
	 var WhiteScore = [];
	 for (var i = 0; i < 15; i++) {
	  BlackScore[i] = [];
	  WhiteScore[i] = [];
	  for (var j = 0; j < 15; j++) {
	   BlackScore[i][j] = 0;
	   WhiteScore[i][j] = 0;
	  }
	 }
	
	 /* 评分方法 */
	 for (var i = 0; i < 15; i++) {
	  for (var j = 0; j < 15; j++) {
	   /* 该点无落子 */
	   if (chessBoard[i][j] == 0) {
	    /* 遍历所有赢法 */
	    for (var k = 0; k < count; k++) {
	     /* 对包含该点的赢法 所对应的赢法统计数组进行加分 -- 说明在该点落子是有价值的 */
	     if (wins[i][j][k]) {
	      /* 如果黑棋在这种赢法中已有1个落子 */
	      if (BlackWin[k] == 1) {
	       BlackScore[i][j] += 200;
	      /* 如果黑棋在这种赢法中已有2个落子 */
	      }else if (BlackWin[k] == 2) {
	       BlackScore[i][j] += 400;
	      /* 如果黑棋在这种赢法中已有3个落子 */
	      }else if (BlackWin[k] == 3) {
	       BlackScore[i][j] += 2000;
	      /* 如果黑棋在这种赢法中已有4个落子 */
	      }else if (BlackWin[k] == 4) {
	       BlackScore[i][j] += 10000;
	      }
	
	      /* 如果白棋在这种赢法中已有1个落子 */
	      if (WhiteWin[k] == 1) {
	       WhiteScore[i][j] += 220;
	      /* 如果白棋在这种赢法中已有2个落子 */
	      }else if (WhiteWin[k] == 2) {
	       WhiteScore[i][j] += 420;
	      /* 如果白棋在这种赢法中已有3个落子 */
	      }else if (WhiteWin[k] == 3) {
	       WhiteScore[i][j] += 2100;
	      /* 如果白棋在这种赢法中已有4个落子 */
	      }else if (WhiteWin[k] == 4) {
	       WhiteScore[i][j] += 20000;
	      }
	     }
	    }
	
	    /* 记录价值最高分和最高价值落子点坐标 */
	    /* 优先级问题  越靠后,优先级越高*/
	
	    /* 1、拦截黑棋 */
	    if (BlackScore[i][j] > max) {
	     max = BlackScore[i][j];
	     u = i;
	     v = j;
	    /* 2、当对黑棋的拦截价值分数相同时 优先选择在拦截基础上对白棋价值分更高的点位 */
	    }else if(BlackScore[i][j] == max){
	     if (WhiteScore[i][j] > WhiteScore[u][v]) {
	      u = i;
	      v = j;
	     }
	    }
	    /* 3、当行白棋和拦截黑棋价值分相同时,优先行走白棋*/
	    if (WhiteScore[i][j] > max) {
	     max = WhiteScore[i][j];
	     u = i;
	     v = j;
	    /* 4、当多个行走白棋的方案价值分相同时,优先选择在行走白棋基础上对黑棋拦截价值分更高的点位 */
	    }else if(WhiteScore[i][j] == max){
	     if (BlackScore[i][j] > BlackScore[u][v]) {
	      u = i;
	      v = j;
	     }
	    }
	   }
	  }
	 }
	
	 /* 计算机AI计算完毕 落子 */
	 oneStep(u, v, false);
	 /* 改变落子点状态 */
	 chessBoard[u][v] = 2; //白棋落子
	 /* 胜负判定*/
	 for (var k = 0; k < count; k++) {
	  if (wins[u][v][k]) {
	   /* 白棋在该赢法下胜利系数 + 1 */
	   WhiteWin[k]++;
	   /* 黑棋不可能在该赢法下胜利 */
	   BlackScore[k] = 6;
	   if (WhiteWin[k] == 5) {
	    window.alert("Computer Win");
	    over = true;
	   }
	  }
	 }
	 /* 如果未结束 改变落子方 */
	 if (!over) {
	  me = !me;
	 }

}
</script>
    <!-- script ends -->
</head>
<body>
	<div align="left" > 
		<a href="javascript:;" onClick="javascript:history.back(-1);">
			<img height="50" width="50"  src="../img/tubiao/1.png" border="0" title="返回上一页" >
		</a>
	</div>
	<div align="center">
		<p style="color:red;font-size:18px;font-weight:bold" align="center">五子棋游戏</p>
	   <canvas id="chess" width="320px" height="320px" align="center"></canvas>
	   <img id="img" src="../img/game_gobang/qipan.jpg" hidden="hidden"/>
	   <div id="restart" class="restart">
            <span>重新开始</span>
        </div>
	</div>
</body>
</html>

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值