<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> * { padding: 0; margin: 0; text-align: center; vertical-align: middle; } </style> </head> <body> <canvas id="one-two">此浏览器可能不支持canvas</canvas> </body> <script type="text/javascript" charset="utf-8"> class OneTwo { constructor(canvasId) { this.rowCount = 3; this.colCount = this.rowCount; this.canvas = document.getElementById(canvasId); this.ctx = this.canvas.getContext("2d"); this.cellWidth = 100; // 单位px this.offsetX = this.cellWidth / 2; this.offsetY = this.offsetX; this.width = this.cellWidth * this.rowCount + this.offsetX * 2; this.height = this.width; this.canvasId = canvasId; this.pieces = []; this.active = 2; // this.status = 1; // 1添加子 2移动子 this.R = this.cellWidth * 0.3; this.hint = []; // 提示位置 this.toMove = {}; // 即将移动的棋子 this.init(); } // 渲染页面 renderUi() { //清除之前的画布 this.ctx.clearRect(0, 0, this.width, this.height); // 重绘画布 this.drawMap(); this.drawPieces(); console.log(this.toMove, "渲染前选择的棋子") this.highLight(); } //初始化 init() { this.initCanvas(); this.drawMap(); this.initPieces(); } // initCanvas() { this.canvas.width = this.width; this.canvas.height = this.height; } // initPieces(){} initPieces() { for(let i = 0; i <= this.rowCount; i++) { this.pieces[i] = []; for(let j = 0; j <= this.colCount; j++) { this.pieces[i][j] = 0; } } console.log(this.pieces); } // 画地图 drawMap() { // 背景 this.ctx.beginPath(); this.ctx.rect(0, 0, this.width, this.height); this.ctx.closePath(); this.ctx.fillStyle = "#0099CC"; this.ctx.fill(); // 画横线 this.ctx.strokeStyle = "black"; this.ctx.beginPath(); for(let i = 0; i <= this.rowCount; i++) { this.ctx.moveTo(0 + this.offsetX, this.cellWidth * i + this.offsetY); this.ctx.lineTo(this.cellWidth * this.rowCount + this.offsetX, this.cellWidth * i + this.offsetY); } this.ctx.stroke(); // 画纵线 this.ctx.beginPath(); for(let i = 0; i <= this.colCount; i++) { this.ctx.moveTo(this.cellWidth * i + this.offsetX, 0 + this.offsetY); this.ctx.lineTo(this.cellWidth * i + this.offsetX, this.cellWidth * this.colCount + this.offsetY); } 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() { //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] !== 0) { this.drawOnePiece(i, j, this.R, this.getColor(this.pieces[i][j])); } } } } // drawOnePiece(i, j, r, color) { var x = i * this.cellWidth + this.offsetX; var y = j * this.cellWidth + this.offsetY; this.drawDot(x, y, r, color); } // 获取某个棋子的颜色 0——空 1——白 2——黑 getColor(num) { var res = ""; 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; } // cango canGo(x, y) { if(this.pieces[x][y] == 0) { return true; } else { return false; } } // 添加棋 add(x, y) { if(this.canGo(x, y)) { this.pieces[x][y] = this.active; // this.drawOnePiece(x,y); this.weed(x, y); this.renderUi(); this.exchange(); console.log(this.pieces, "当前棋局") } else { console.warn("这里貌似不能添加棋子"); } } // 是否可以移动 oneCanMove(x, y, oneSide) { var moveRange = this.getMoveRange(x, y, oneSide); if(moveRange.length) { return true; } else { return false; } } // 所有的棋子是否可以移动 hasCanMovePiece(oneSide) { var oneSideCanMove = false; for(let i = 0, len = this.pieces.length; i < len; i++) { for(let j = 0, len1 = this.pieces[i].length; j < len1; j++) { if(this.pieces[i][j] === oneSide) { if(this.oneCanMove(i, j, oneSide)) { oneSideCanMove = true; break; } } } } return oneSideCanMove; } // 获取某一方的棋子数量 getCount(oneSide) { var count = 0; for(let i = 0, len = this.pieces.length; i < len; i++) { for(let j = 0, len1 = this.pieces[i].length; j < len1; j++) { if(this.pieces[i][j] === oneSide) { count++; } } } return count; } // 没有棋走,自己拔出自己的一颗子 weedOne(x, y) { this.pieces[x][y] = 0; } // 转换状态从添加棋子到移动棋子 changeStatus() { console.log("状态转换了"); this.status = 2; } // 当棋盘下满的时候转换状态。下满的时候黑方+白方的总数等于16 wetherChangeStatus() { console.log("判断是否要转换状态", this.getCount(1) + this.getCount(2)) if(this.getCount(1) + this.getCount(2) == 16) { return true; } else { return false; } } // 切换角色(换着走棋) exchange() { this.active = this.active == 1 ? 2 : 1; } // 获取敌方数字 getEnemy(oneSide) { return oneSide == 1 ? 2 : 1; } // 选择移动的棋子 chooseToMove(x, y, oneSide) { if(this.oneCanMove(x, y, oneSide)) { this.toMove.x = x; this.toMove.y = y; //this.highLight(); } else { delete this.toMove.x; delete this.toMove.y; console.warn("这个棋子不可以移动"); } console.log(this.toMove, "选择后的要移动的棋子") } // 判断移动的最终位置是否在移动范围内 inRange(x, y, oneSide) { var moveRange = this.getMoveRange(this.toMove.x, this.toMove.y, oneSide); console.log(moveRange, "移动范围"); var flag = false; for(let i = 0, len = moveRange.length; i < len; i++) { if(x == moveRange[i].x && y == moveRange[i].y) { flag = true; break; } } return flag; } // 移动 1.选择需要移动的棋子 2.点击推荐的可以移动的位置 3.之前的位置赋值为空,结束的位置赋值为当前棋子 move(x, y) { if(Object.keys(this.toMove).length) { // 已经选了将要移动的棋子 移动 if(this.pieces[x][y] == this.active) { // 这时候想移动别的棋子 console.log("重新选择要移动的棋子x:" + x + ";y:" + y); this.chooseToMove(x, y, this.active); //this.renderUi(); } else { if(this.inRange(x, y, this.active)) { // 移动当前棋子 删除己选择的移动棋子 去除已选择状态 console.log("移动棋子"); this.pieces[x][y] = this.active; this.pieces[this.toMove.x][this.toMove.y] = 0; this.weed(x, y); this.exchange(); delete this.toMove.x; delete this.toMove.y; //this.renderUi(); } else { console.log("移动范围超标了,每次只可以横向或纵向移动一格"); } } } else { // 选择要移动的棋子 console.log("选择要移动的棋子x:" + x + ";y:" + y); this.chooseToMove(x, y, this.active); //this.renderUi(); } this.renderUi(); } // goStep goStep(x, y) { if(this.status == 1) { // 添加 this.add(x, y); if(this.wetherChangeStatus()) { this.changeStatus(); } } else { // 拔子 移动 if(this.hasCanMovePiece(this.active)) { // 移动 console.log("移动主流程"); this.move(x, y); this.getVictor(); } else { //拔子 console.log("拔子主流程"); if(this.pieces[x][y] == this.active) { this.weedOne(x, y); this.exchange(); this.renderUi(); this.getVictor(); } else { console.log("子不是你的,拔个锤子"); } } } } // 给选择的棋子加上高亮标记 highLight() { console.log(this.toMove); if(!Object.keys(this.toMove).length) { return; } console.log("要开始画了") var x = this.toMove.x; var y = this.toMove.y; var pArr = ["lt", "ld", "rd", "rt"]; for(let i = 0, len = pArr.length; i < len; i++) { var xx = x * this.cellWidth + this.offsetX; var yy = y * this.cellWidth + this.offsetY; this.drawRightAngle(xx, yy, this.R, 10, pArr[i]); } } // 画直角 以圆心为起点,2r为边的正方形的角,length为画的线的长度,p为需要画的角(如:左上角lt) drawRightAngle(x, y, r, length, p, color) { color = color || "yellow"; var nd = this.nd(p); var h = nd.h; var v = nd.v; this.ctx.beginPath(); this.ctx.strokeStyle = color; this.ctx.moveTo(x + h * r, y + v * r); this.ctx.lineTo(x + h * r - h * length, y + v * r); this.ctx.moveTo(x + h * r, y + v * r); this.ctx.lineTo(x + h * r, y + v * r - v * length); this.ctx.closePath(); this.ctx.stroke(); } // 显示提示位置 // 显示移动范围 getMoveRange(x, y, oneSide) { var moveRange = []; if(this.pieces[x][y] === oneSide) { var dArr = ["r", "d", "l", "t"]; var direction, h, v; for(let i = 0, len = dArr.length; i < len; i++) { direction = this.nd(dArr[i]); h = direction.h; v = direction.v; if(this.pieces[x + h] && this.pieces[x + h][y + v] === 0) { moveRange.push({ x: x + h, y: y + v }); } } } else { console.log("空位置和敌方的棋子不可以移动,请移动自己的棋子到空位置"); } return moveRange; } // 获取赢家 getVictor() { var white = this.getCount(1); var black = this.getCount(2); if(white == 0) { setTimeout(() => { alert("黑棋赢咧"); }, 50); } else if(black == 0) { setTimeout(() => { alert("白棋赢咧"); }, 50); } } // 拔子 weed(x, y) { var dArr = ["r", "d", "l", "t"]; var direction, h, v, np; for(let i = 0, len = dArr.length; i < len; i++) { direction = this.nd(dArr[i]); h = direction.h; v = direction.v; np = this.np(x, y, dArr[i]); // 先看自己有没有凑够两个子,凑够了才可以吃子 if(np === 0) { if(this.pieces[x + h] && this.pieces[x + h][y + v] === this.active) { //AA?? if(this.pieces[x + 2 * h] && this.pieces[x + 2 * h][y + 2 * v] === this.getEnemy(this.active)) { //AAB? if(this.pieces[x + 3 * h] && this.pieces[x + 3 * h][y + 3 * v] === this.getEnemy(this.active)) { //AABB this.pieces[x + 2 * h][y + 2 * v] = 0; this.pieces[x + 3 * h][y + 3 * v] = 0; } else if(this.pieces[x + 3 * h] && this.pieces[x + 3 * h][y + 3 * v] === this.active) { //AABA continue; } else { // AABO this.pieces[x + 2 * h][y + 2 * v] = 0; } } else { // AAA? 或AAO? continue; } } else { //AB??或AO?? continue; } } else if(np === 1) { if(this.pieces[x + h] && this.pieces[x + h][y + v] === this.active) { //?AA? if(this.pieces[x - h] && this.pieces[x - h][y - v] === this.getEnemy(this.active)) { //BAA? if(this.pieces[x + 2 * h] && this.pieces[x + 2 * h][y + 2 * v] === this.getEnemy(this.active)) { //BAAB continue; } else if(this.pieces[x + 2 * h] && this.pieces[x + 2 * h][y + 2 * v] === this.active) { //BAAA continue; } else { //BAAO this.pieces[x - h][y - v] = 0; } } else if(this.pieces[x - h] && this.pieces[x - h][y - v] === this.active) { // AAA? continue; } else { //OAA? if(this.pieces[x + 2 * h] && this.pieces[x + 2 * h][y + 2 * v] === this.getEnemy(this.active)) { this.pieces[x + 2 * h][y + 2 * v] = 0; } else { continue; } } } else if(this.pieces[x + h] && this.pieces[x + h][y + v] === this.getEnemy(this.active)) { //?AB? if(this.pieces[x - h] && this.pieces[x - h][y - v] === this.active) { //AAB? if(this.pieces[x + 2 * h] && this.pieces[x + 2 * h][y + 2 * v] === this.getEnemy(this.active)) { //AABB this.pieces[x + h][y + v] = 0; this.pieces[x + 2 * h][y + 2 * v] = 0; } else if(this.pieces[x + 2 * h] && this.pieces[x + 2 * h][y + 2 * v] === this.active) { //AABA continue; } else { //AABO this.pieces[x + h][y + v] = 0; } } else { //OAB? BAB? continue; } } else { //?AO? continue; } } else if(np === 2) { if(this.pieces[x + h] && this.pieces[x + h][y + v] === this.active) { //??AA if(this.pieces[x - h] && this.pieces[x - h][y - v] === this.getEnemy(this.active)) { //?BAA if(this.pieces[x - 2 * h] && this.pieces[x - 2 * h][y - 2 * v] === this.getEnemy(this.active)) { //BBAA this.pieces[x - 2 * h][y - 2 * v] = 0; this.pieces[x - h][y - v] = 0; } else if(this.pieces[x - 2 * h] && this.pieces[x - 2 * h][y - 2 * v] === this.active) { //ABAA continue; } else { //OBAA this.pieces[x - h][y - v] = 0; } } else { // ?OAA 或?AAA continue; } } else if(this.pieces[x + h] && this.pieces[x + h][y + v] === this.getEnemy(this.active)) { //??AB if(this.pieces[x - h] && this.pieces[x - h][y - v] === this.active) { //?AAB if(this.pieces[x - 2 * h] && this.pieces[x - 2 * h][y - 2 * v] === this.getEnemy(this.active)) { //BAAB // this.pieces[x-h][y-v] = 0; // this.pieces[x-2*h][y-2*v] = 0; continue; } else if(this.pieces[x - 2 * h] && this.pieces[x - 2 * h][y - 2 * v] === this.active) { //AAAB continue; } else { //OAAB this.pieces[x + h][y + v] = 0; } } else { //?BAB或?OAB continue; } } else { //??AO if(this.pieces[x - h] && this.pieces[x - h][y - v] === this.active) { //?AAO if(this.pieces[x - 2 * h] && this.pieces[x - 2 * h][y - 2 * v] === this.getEnemy(this.active)) { //BAAO this.pieces[x - 2 * h][y - 2 * v] = 0; } else { //AAAO或OAAO continue; } } else { //?BAO 或?OAO continue; } } } else if(np === 3) { if(this.pieces[x - h] && this.pieces[x - h][y - v] === this.active) { //??AA if(this.pieces[x - 2 * h] && this.pieces[x - 2 * h][y - 2 * v] === this.getEnemy(this.active)) { //?BAA if(this.pieces[x - 3 * h] && this.pieces[x - 3 * h][y - 3 * v] === this.getEnemy(this.active)) { //BBAA this.pieces[x - 2 * h][y - 2 * v] = 0; this.pieces[x - 3 * h][y - 3 * v] = 0; } else if(this.pieces[x - 3 * h] && this.pieces[x - 3 * h][y - 3 * v] === this.active) { //ABAA continue; } else { // OBAA this.pieces[x - 2 * h][y - 2 * v] = 0; } } else { // ?AAA 或?OAA continue; } } else { //??BA或??OA continue; } } } } // 方向数字化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; } // 某个方向上当前(x,y)是第几个位置 np(x, y, direction) { var d = this.nd(direction); if(d.h !== 0) { if(d.h === 1) { return x; } else { // -1 return 3 - x; } } else { if(d.v === 1) { return y; } else { //-1 return 3 - y; } } console.error("np出错了"); return 0; } // 深拷贝 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."); } } </script> <script type="text/javascript"> var oneTwo = new OneTwo("one-two"); var canvas = document.getElementById("one-two"); console.log(canvas.getBoundingClientRect()); var offset; canvas.addEventListener("click", function(e) { offset = canvas.getBoundingClientRect(); var x = Math.floor((e.clientX - offset.left) / oneTwo.cellWidth); var y = Math.floor((e.clientY - offset.top) / oneTwo.cellWidth); console.log(x, y, "点击位置"); // 走棋 oneTwo.goStep(x, y); }, false); </script> </html>
玩法简介:
1. 一只一担是流传在中国米黄玉之乡的谭山镇的一种双人、益智、棋牌类游戏。棋盘是4*4的方格线,棋子放在线与线的交界处。棋子可以用任意两种可以区分的道具,如纸团、石子、木棍等。因此随时随地,只要在地上画个4*4的方格,弄几个石子什么的就可以玩了,非常的方便。
这个游戏分为两个阶段——谋篇布阵和征战。
刚开始,双方在棋盘上抢占有利位置,并互相征战。棋盘上位置占满后,一方弃掉自己的一个子,棋盘上就有空位置了,双方就开始交替移动棋子,进行征战,没有可以移动的棋子时,弃掉自己的一个棋子,轮到对方走棋。直到最后一方没有棋子了结束战斗。
吃子规则
两个(一担)可以吃掉对方的一个或者两个(一担)。具体图形如下(A——甲方,B——乙方,O——空位置):
1. AABO——甲由?ABO,在第一个位置走一个棋后变成AABO;或者由A?BO,在第二个位置走一个棋后变成AABO。则第三个位置的乙方棋子被剔除棋盘,变成空位置,再由双方来争夺这个位置。
2.OAAB——甲由OA?B,在第三个位置走一个棋后变成OAAB;或者由O?AB,在第二个位置有一个棋后变成功能OAAB。则第四个位置的乙方棋子被剔除棋盘,变成空位置,再由双方来争夺这个位置。
3. AABB——甲由?ABB,在第一个位置走一个棋后变成AABB;或者由A?BB,在第二个位置有一个棋后变成功能AABB。则第三和第四个位置的乙方棋子都被剔除棋盘,变成空位置,再由双方来争夺这个位置。
其他的情况不可以吃棋。如以下两个图形。
1. AABA
2.AAAB
通常用这两种棋来防守,防止对方吃掉自己的棋子。
赶紧复制以下去玩玩吧~