• 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

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

    赶紧复制以下去玩玩吧~

  • 相关阅读:
    git常用命令及多人协同开发及遇到的问题
    LightOJ
    LightOJ
    LightOJ
    LightOJ
    LightOJ
    LightOJ
    LightOJ
    LightOJ
    Codeforces Round #604 (Div. 2) E. Beautiful Mirrors
  • 原文地址:https://www.cnblogs.com/zhaodesheng/p/9723434.html
Copyright © 2020-2023  润新知