简单的 js 版单机五子棋 demo

468 阅读4分钟

废话开篇:简单用 canvas 绘制跟触点跟踪来实现一个 js版单机五子棋 demo,这里没有什么特别高级的东西,内容纯属娱乐。

屏幕录制2021-11-09 上午10.22.45.gif

步骤一、先画一个棋盘

这里直接上一段简单 html 代码,内容就是一个 canvas 标签。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<script src="wz.js" type="text/javascript" charset="utf-8"></script>
	<style type="text/css">
		#canvas{
			background-color: aliceblue;
			margin-top: 50px;
			margin-left: 50px;
		}
	</style>
	<body>
		<canvas id="canvas" width="606" height="606"></canvas>
	</body>
	<script>
		window.$wzObj.initMap()
	</script>
</html>

步骤二、在 canvas 标签内画好棋盘

js 文件里声明了一个 wzObj 对象,把所有的任务执行都绑定在这个 wzObj 对象上面。

wzObj 对象添加一个 initMap 的方法,这里就进行了 3 步:

1、获取 canvas 画布。

2、计算网格线定位参数。

3、绘制网格横线、竖线。

wzObj.initMap = function(){
		//步骤一 拿到画板
		var canvas = document.getElementById('canvas')
                //添加画板鼠标点击 point
		canvas.addEventListener('click', function(e) {
			
			var x = event.pageX - 50
		        var y = event.pageY - 50
                        //绘制棋子
			wzObj.draw(x,y);
		})
                //步骤二
		var mapWidth = canvas.width - 1;
		var lineNums = 11;
		var lineWidth = 1;
		var sap = mapWidth / lineNums;
		this.sap = sap;
		// 拿到上下文
		var context = canvas.getContext('2d');
		// 设置线条的颜色
		context.strokeStyle = '#000';
		// 设置线条的宽度
		context.lineWidth = lineWidth;
		
                //步骤三
		for(var i = 1;i < lineNums;i++){
                
                         //绘制竖线
                         //开始绘制路径
			 context.beginPath();
			 // 起点
			 context.moveTo(i * sap + 0.5, sap);
			 // 终点
			 context.lineTo(i * sap + 0.5, mapWidth - sap);
			 //填充颜色
			 context.strokeStyle="#000";
                         //进行填充
			 context.stroke();
                         //关闭绘制路径
			 context.closePath();
			 
                         //绘制横线
			 context.beginPath();
			 // 起点
			 context.moveTo(sap,i * sap + 0.5);
			 // 终点
			 context.lineTo(mapWidth - sap,i * sap + 0.5);
			 
			 context.strokeStyle="#000";
			 context.stroke();
			 context.closePath();
		}
	}

步骤三、判断画布鼠标触点位置,进行绘制黑白棋子

初始化棋盘记录数据:

recordArr:记录当前棋盘所有位置落子情况 0:无落子,1:黑子,2:白子。初始化全部重置为 0.

black:记录下一手落子颜色。true:黑子,false:白子。

var wzObj = {}
wzObj.recordArr = [];
wzObj.black = true;
//初始化全部统计为 0
for(var i = 0;i < 10;i++){
	var arr = [];
	for(var j = 0;j < 10;j++){
		arr.push(0);
	}
	wzObj.recordArr.push(arr);
}

进行触点计算及绘制

wzObj.draw = function(x,y){
                //不在棋盘内,不进行绘制,x、y参数值为当前鼠标 point 的 x值及y值
		if(x < 55 || y < 55 || x > 552 || y > 552){
			return;
		}
                //棋盘x轴的偏移量
		var i = x / this.sap;
                //Math.round 把一个数字舍入为最接近的整数,这里并没有四舍五入,只招附近的整数点
		i = Math.round(i);
                //棋盘y轴偏移量
		var j = y / this.sap;
		j = Math.round(j);
                //如果当前计算的棋盘位置已落子,不进行绘制
		if(this.haveRecordAtPoint(i-1,j-1)){
			return;
		}
                //进行绘制
		var canvas = document.getElementById("canvas");
		var context = canvas.getContext("2d");  
                //判断当前绘制的棋子的颜色
	        context.fillStyle = this.black ? "#000" : "#FFF";
		context.beginPath();
                //绘制圆形。
		context.arc(this.sap * i, this.sap * j, 15, 0, 2*Math.PI, true);
		context.closePath();
		context.stroke();
                //进行内部填充
		context.fill();
		console.log('x='+x + 'y='+y);
		console.log('i='+i + 'j='+j);
                //记录当前落子点
		this.record(i-1,j-1);
                //判断是否有5子链接,进行胜负判断。
		if(this.judgeIsComplete(i-1,j-1)){
			var that = this;
			setTimeout(function(){
				var name = that.black  ? "黑子" : "白子";
				alert(name + "赢了");
			},500);
		} else {
                        //没有判断出输赢,棋子落子颜色变更
			this.black = !this.black;
		}	
	}

判断是否已落子

        //判断是否已落子
	wzObj.haveRecordAtPoint = function(i,j){
		var arrX = this.recordArr[i];
		var y = arrX[j];
		return (y != 0);
	}

记录落子

        //记录落子
	wzObj.record = function(i,j){
		var arrX = this.recordArr[i];
		var y = arrX[j];
		arrX[j] = (this.black == true) ? 1 : 2;
	}

步骤四、根据当前结束的落子位置进行棋盘上同颜色棋子整体输赢判断

通过当前落子的位置,从横向、纵向、左上到右下、右上到左下的顺序进行判断周围是否有 5 子链接

        //计算是否有链接5子部分
	wzObj.judgeIsComplete = function(i,j){
		var bj = this.black ? 1 : 2;
		var sameCount = 0;
		//计算横向
		//向左
		var arrX = this.recordArr[i];
		for(var x = j;x >= 0;x--){
			var val = arrX[x];
			if(val == bj){
				sameCount++;
			} else {
				break;
			}
		}
		//向右
		for(var x = j+1;x <= arrX.length;x++){
			var val = arrX[x];
			if(val == bj){
				sameCount++;
			} else {
				break;
			}
		}
                //从左到右,检测,数量 >= 5 输赢判断成立
		if(sameCount >= 5){
			return true;
		}
		
		//计算纵向
		//向上
		sameCount = 0;
		for(var y = i;y >= 0;y--){
			var val = this.recordArr[y][j];
			if(val == bj){
				sameCount++;
			} else {
				break;
			}
		}
		//向下
		for(var y = i + 1;y < this.recordArr.length;y++){
			var val = this.recordArr[y][j];
			if(val == bj){
				sameCount++;
			} else {
				break;
			}
		}
                //从上到下,检测,数量 >= 5 输赢判断成立
		if(sameCount >= 5){
			return true;
		}
		//左上-右下
		sameCount = 0;
		var y = i;
		for(var x = j;x >= 0;x--){
			if(y >= 0){
				var val = this.recordArr[y][x];
				if(val == bj){
					sameCount++;
				} else {
					break;
				}
			}
			y-=1;
		}
		y = i + 1;
		for(var x = j + 1;x < this.recordArr.length;x++){
			if(y <= this.recordArr.length){
				var val = this.recordArr[y][x];
				if(val == bj){
					sameCount++;
				} else {
					break;
				}
			}
			y+=1;
		}
                
                //从左上到右下,检测,数量 >= 5 输赢判断成立
		if(sameCount >= 5){
			return true;
		}
		
		//右上-左下
		sameCount = 0;
		y = i;
		for(var x = j;x < this.recordArr.length;x++){
			if(y >= 0){
				var val = this.recordArr[y][x];
				if(val == bj){
					sameCount++;
				} else {
					break;
				}
			}
			y-=1;
		}
		y = i + 1;
		for(var x = j - 1;x >= 0;x--){
			if(y <= this.recordArr.length){
				var val = this.recordArr[y][x];
				if(val == bj){
					sameCount++;
				} else {
					break;
				}
			}
			y+=1;
		}
                //从右上到左下,检测,数量 >= 5 输赢判断成立
		if(sameCount >= 5){
			return true;
		}
		return false;
	}

好了,极其简单的五子棋 demo 就写好了,里面没啥技术高的内容,纯属娱乐,代码拙劣,大神勿笑。