欢迎关注得胜的git仓库

js+canvas 一只一担小游戏

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

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

赶紧复制以下去玩玩吧~

posted on 2018-09-29 14:13  web得胜  阅读(544)  评论(0编辑  收藏  举报

导航

感谢观看web得胜的博客,如果您觉得对你有帮助,请点赞支持一下哦~。发现问题请留言指正,谢谢!