<!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

通常用这两种棋来防守,防止对方吃掉自己的棋子。

赶紧复制以下去玩玩吧~

05-15 05:28