简单扑克游戏之基本逻辑

扑克游戏.gif

这是两个人间的简单扑克游戏,每人27张牌,由服务器随机分成两组不同的数组传递给客户端。

基本逻辑已实现,剩下扑克牌逻辑:
  • 1.用户进入登录界面,点击登录按钮,若当前已有一个人在等待,则直接进入游戏,否则一直等待,直到第二个人登录;
  • 2.用户在游戏中随时可退出,刷新页面即视为退出,此时双方都回到登录界面,需要重新登录;
  • 3.依据哪方拿到 黑桃♠3,哪方就先出牌;
  • 4.假设A先出牌,A出牌给B,B上方出现A发过来的牌,换B出牌,这时有出牌和放弃两个选项。出牌同样发送选中牌的数据,放弃则是不刷新桌上牌列,将出牌权给A。

JS

var socket = io();  //传递给服务器用户Id
var wrapper = ".wrapper";
var htmlLogin = "<div class='login'><button type='button' id='login'>登录</button> </div>";
var htmlWait = "<div class='waiting'> <h3>请等待另一位玩家加入。。。</h3> </div>";
var htmlPoker = "<div class='wrap'> <div class='box-upper'></div> <div class='box-center'> <div class='preview-above' id='preview-above'></div> <div class='preview-below' id='preview-below'></div> </div> <div class='button-turn hide-block'> <button class='discard' id='discard'>出牌</button> <button class='abandon' id='abandon'>放弃</button> </div> <div class='box-below' id='box-below'></div></div>";
var htmlWin = "<div class='mask'><div class='content'>WIN</div> <button type='button' id='reload'>确定</button></div>";
var htmlDefeat = "<div class='mask'><div class='content'>Defeat</div> <button type='button' id='reload'>确定</button></div>";

var INIT = "INIT";
var WAIT = "WAIT";
var DISCARD = "DISCARD";
var GAMEOVER = "GAMEOVER";
var RESTART = "RESTART";

$(init);

function init() {
    //绑定点击事件
    $("body").on("click", clickEvent);
    //初始化socket和登录界面
    pkObj.init();
}

//点击事件
function clickEvent(e) {
    var target = e.target;
    var that = $(target);

    switch (pkObj.data.status) {
        case INIT:  //未登录状态
            doInit();
            break;
        case DISCARD:   //出牌状态
            doDiscard(that);
            break;
        case GAMEOVER:  //游戏结束状态
            doRestart();
            break;
        default:
            break;
    }
}
//pkObj
var pkObj = {
    data: {
        type: 0,    //出牌类型
        discardList: 0, //出牌数组
        remain: 27,    //我方牌的剩余量
        from: 0,    //我方id
        to: 0,  //对方id
        before: false,  //先出牌或对方放弃
        status: INIT    //状态:INIT初始化, DISCARD出牌,GAMEOVER游戏结束
    },
    init: function () {
        //初始化socket
        socketInit();
        //加载登录界面
        $(wrapper).append(htmlLogin);
    }

};

//初始化socket
function socketInit() {

    //等待状态
    socket.on("waiting", function () {
        $(wrapper).html("");
        $(wrapper).append(htmlWait);
        pkObj.data.status = WAIT;
    });

    //进入打牌界面
    socket.on("start poker", function (data) {
        pkObj.data.to = data.to;
        $(wrapper).html("");
        $(wrapper).append(htmlPoker);
        if(data.before == true) {
            pkObj.data.before = true;
            $(".button-turn").removeClass("hide-block");
            $("#abandon").attr('disabled',"true");
            pkObj.data.status = DISCARD;
        } else {
            pkObj.data.status = WAIT;
        }
        poker(data.pokerList, 27);
    });

    //第三人登录显示拥挤
    socket.on("crowded", function () {
        alert("棋牌室拥挤,请稍后再试。。。");
    });

    //对方退出全部初始化
    socket.on("exit", function () {
        $(wrapper).html("");
        $(wrapper).append(htmlLogin);
        pkObj.data.status = RESTART;
    });

    //接受对方的牌
    socket.on("receive discard", function (data) {
        var num = data.num;
        var length = $(".opposite").length;
        $("#preview-above").html("");
        $("#preview-below").html("");
        for(var index in data.discard) {
            $("#preview-above").append(data.discard[index]);
        }
        $(".button-turn").removeClass("hide-block");
        // $(".opposite:eq(" + i + ")").remove();
        $(".box-upper").html("");
        oppositePoker(length - num);
        pkObj.data.status = DISCARD;
    });

    //对方放弃出牌
    socket.on("receive abandon", function () {
        pkObj.data.before = true;
        $("#abandon").attr('disabled',"true");
        $("#preview-above").html("");
        $(".button-turn").removeClass("hide-block");
        pkObj.data.status = DISCARD;
    });

    //比赛结果
    socket.on("receive result", function (data) {
        pkObj.data.status = GAMEOVER;
        if(data == pkObj.data.from) {
            $(wrapper).append(htmlWin);
        } else {
            $(wrapper).append(htmlDefeat);
        }
    });
}

//游戏结束
function doRestart() {
    location.reload();
}

//登录状态
function doInit() {
    //获得唯一的id
    window.id = new Date().getTime()+""+Math.floor(Math.random()*899+100);
    pkObj.data.from = id;
    socket.emit("add user", id);
}
//出牌状态
function doDiscard(that) {
    var element = that.attr("id");
    var temp = element.replace(/[p]([0-9]+)/g, "p");
    switch (temp) {
        //p表示点击了选择的牌
        case "p":
            if(that.parent().attr("id") == "box-below") {
                if(that.hasClass("click-up")) {
                    that.removeClass("click-up");
                } else {
                    that.addClass("click-up");
                }
            }
            break;
        //点击出牌按钮
        case "discard":
            if($(".box-below").find(".click-up").length == 0) {
                alert("请选择要出的牌,若没有请点击放弃");
            } else {
                var list = new Array();         //list中保存选中牌的整个div代码
                var aboveList =  new Array();   //aboveList 对方的牌
                var belowList = new Array();    //belowList 我选中的牌
                var i = 0;
                var j = 0;
                var k = 0;
                // $("#preview-above").html("");
                // $("#preview-below").html("");
                $("#preview-above").find(".poker").each(function () {
                    var pokerId = $(this).attr("id");
                    pokerId = pokerId.replace(/[p]([0-9]+)/g, "$1"); //获取选中的牌的id(删掉首字母p)
                    aboveList[j] = getPokerFace(pokerId);
                    j++;
                });
                $("#box-below").find(".click-up").each(function () {
                    var pokerId = $(this).attr("id");
                    pokerId = pokerId.replace(/[p]([0-9]+)/g, "$1"); //获取选中的牌的id(删掉首字母p)
                    belowList[k] = getPokerFace(pokerId);
                    k++;
                });
                //先对选中的牌进行比较
                if(compare(aboveList, belowList) || (pkObj.data.before && checkPokerType(belowList) != 0)) {
                    $("#preview-above").html("");
                    $("#preview-below").html("");
                    $(".click-up").each(function () {
                        list[i] = $(this).prop("outerHTML");    //获取选中的牌的整个div代码
                        $(this).removeClass("click-up");
                        $("#preview-below").append(list[i]);
                        $(this).remove();
                        i++;
                    });
                    pkObj.data.remain-=list.length;
                    var data = {
                        discard: list,
                        from: pkObj.data.from,
                        to: pkObj.data.to,
                        num: list.length,
                        remain: pkObj.data.remain
                    };
                    pkObj.data.before = false;
                    $("#abandon").removeAttr("disabled");
                    socket.emit("discard", data);
                    $(".button-turn").addClass("hide-block");
                    pkObj.data.status = WAIT;
                } else {
                    alert("出牌不符合规则!");
                }
            }
            break;
        //点击放弃按钮
        case "abandon":
            $(".click-up").each(function () {
                $(this).removeClass("click-up");
            });
            socket.emit("abandon", pkObj.data.to);
            $(".button-turn").addClass("hide-block");
            pkObj.data.status = WAIT;
            break;
        default:
            break;
    }
}

//初始化扑克牌
function poker(list, n) {}

//展示对方的牌
function oppositePoker(n) {}

//根据余数排序
function sortNumber(a, b) {}

//改变特殊牌的值
function changeNum(n, m) {}

//根据序号指定精灵图的位置
function getPos(index) {}

//检查和确定出牌的类型
function checkPokerType(pokerList) {}

//将选择出的牌和对方出的牌进行比较
function compare(list1, list2) {}

//返回每张牌的面值
function getPokerFace(n) {}

服务器端

//从一个给定的数组arr中,随机返回num个不重复项
function getArrItems(arr, num) {
    var temp = new Array();
    var result = new Array();

    for (var index in arr) {
        temp.push(arr[index]);
    }
    for (var i = 0; i < num; i++) {
        if (temp.length > 0) {
            var arrIndex = Math.floor(Math.random() * temp.length);
            result[i] = temp[arrIndex];
            temp.splice(arrIndex, 1);
        } else {
            break;
        }
    }
    return result;
}
//从一个给定的数组arr中,随机返回num个不重复项
function getArrSubtract(arr, sub) {
    var temp1 = new Array();
    var temp2 = new Array();
    for (var index in arr) {
        temp1.push(arr[index]);
    }
    for (var index in sub) {
        temp2.push(sub[index]);
    }
    for (var i = temp1.length - 1; i >= 0; i--) {
        a = temp1[i];
        for (var j = temp2.length - 1; j >= 0; j--) {
            b = temp2[j];
            if (a == b) {
                temp1.splice(i, 1);
                temp2.splice(j, 1);
                break;
            }
        }
    }
    return temp1;
}

function getPoker() {
    var list = new Array();
    var result = {};
    for (var i = 0; i < 54; i++) {
        list[i] = i + 1;
    }
    var poker1 = getArrItems(list, 27);
    var poker2 = getArrSubtract(list, poker1);

    result = {
        poker1: poker1,
        poker2: poker2
    };

    return result;
}

//poker
var io = require('socket.io').listen(server);
var count = 0;
var user = {};
var first;
var second;
io.on('connection',
function(socket) {

    //用户登录
    socket.on('add user', function(id) {

        console.log("user login");
        count++;
        user[id] = socket;
        socket.name = id;

        if (count == 1) {    //只有一个人登录时
            first = id;
            user[first].emit("waiting");
       
        } else if (count == 2) {     //有两个人登录时
            second = id;
            var result = getPoker();
            var data1 = {
                to: second,
                pokerList: result.poker1,
                before: false
            };
            var data2 = {
                to: first,
                pokerList: result.poker2,
                before: false
            };
            //判断谁拥有黑桃3
            if (result.poker1.indexOf(29) != -1) {
                data1.before = true;
            } else {
                data2.before = true;
            }
            user[first].emit("start poker", data1);
            user[second].emit("start poker", data2);
        } else if (count > 2) {    //大于两人登录时显示繁忙,并删除这个socket
            user[id].emit("crowded");
            count = 2;
            delete user[id];
        }
    });
    //用户退出
    socket.on('disconnect', function() {
        //其中一方退出则全部回到起始页面
        if (count == 1) {
            delete user[socket.name];
        } else if (count == 2) {
            var person = (socket.name == first) ? second: first;
            user[person].emit("exit");
            delete user[first];
            delete user[second];
        }
        count = 0;
    });
    //用户出牌
    socket.on('discard', function(data) {
        var result = {
            discard: data.discard,
            num: data.num
        };
        user[data.to].emit("receive discard", result);
    });
    //放弃出牌
    socket.on("abandon", function(data) {
        user[data].emit("receive abandon");
    });
});

总结:

  • 将点击事件封装到一个函数中,获得点击页面获得被点击元素的id,将id进行Switch
$("body").click(function(e) { // 在页面任意位置点击而触发此事件
      $(e.target).attr("id");       // e.target表示被点击的目标
})
  • .sort()函数
//返回值:  对数组的引用。请注意,数组在原数组上进行排序,不生成副本。
arrayObject.sort(sortby);
//从大到小
function sortNumber(a, b) {
    return b - a;
}
//根据余数排序
function sortNumber(a, b) {
    var x = changeNum(a % 13, a);
    var y = changeNum(b % 13, b);
    return y - x;
}
  • jQuery :eq() 选择器
//选取第二个 <p> 元素:
$("p:eq(1)")
  • 生成时间加上随机数的唯一id
window.id = new Date().getTime()+""+Math.floor(Math.random()*899+100);
  • 获得父元素的id值
that.parent().attr("id") == "box-below"
  • 判断是否存在某一className的元素
if($(".box-below").find(".click-up").length == 0)
  • 获得指定元素的整个div值
list[i] = $(this).prop("outerHTML");
  • 删除元素
$(this).remove();
  • indexOf() 判断数组中是否存在某一值
/*indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
如果要检索的字符串值没有出现,则该方法返回 -1。*/
stringObject.indexOf(searchvalue,fromindex);
//fromindex可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。
  • 取随机数和数组相减,传参数后要新建一个数组,将传入的数组复制过来,用于运算,而不要直接操作传入的数组;
//从一个给定的数组arr中,随机返回num个不重复项
function getArrItems(arr, num) {
    var temp = new Array();
    var result = new Array();

    for (var index in arr) {
        temp.push(arr[index]);
    }
    for (var i = 0; i < num; i++) {
        if (temp.length > 0) {
            var arrIndex = Math.floor(Math.random() * temp.length);
            result[i] = temp[arrIndex];
            temp.splice(arrIndex, 1);
        } else {
            break;
        }
    }
    return result;
}
//数组相减
function getArrSubtract(arr, sub) {
    var temp1 = new Array();
    var temp2 = new Array();
    for (var index in arr) {
        temp1.push(arr[index]);
    }
    for (var index in sub) {
        temp2.push(sub[index]);
    }
    for (var i = temp1.length - 1; i >= 0; i--) {
        a = temp1[i];
        for (var j = temp2.length - 1; j >= 0; j--) {
            b = temp2[j];
            if (a == b) {
                temp1.splice(i, 1);
                temp2.splice(j, 1);
                break;
            }
        }
    }
    return temp1;
}
  • CSS精灵图使用方法
//随便一个写div,设置要显示小图尺寸
width: 90px;  
height: 120px;
background: url("poker.png") no-repeat;   //用于不重复地将图片显示
background-position: -1080px -480px;  //两个参数,要显示小图的位置参数,切记都是负的
  • CSS画网格


    网格.png
.grid {
    width: 400px;
    height: 400px;
    background:    //关键部分,每格40*40,将39px设置透明,就显示出一条1px的线条
        -webkit-linear-gradient(top, transparent 39px, #000 40px),
        -webkit-linear-gradient(left, transparent 39px, #000 40px);
    background-size: 40px 40px;
}
  • CSS动画
transition: all .2s linear;   //设置动画属性
-webkit-transform:rotate(-90deg);   //旋转一定角度
//获取键盘输入
$("body").keydown(function (event) {
        var keyCode = event.keyCode;
}
 //设置按键延迟
setTimeout(function () {
      purse = false;
}, 200);
  • jQuery CSS 操作 - offset() 方法
    position()获取元素top和left
var boxLeft = box.position().left;
var boxTop = box.position().top;

offset()方法返回或设置匹配元素相对于文档的偏移(位置)。
使用函数来设置偏移坐标

$(selector).offset(function(index, oldoffset));
.
$(document).ready(function() {
    $("button").click(function() {
        $("p").offset(function(n, c) {
            newPos = new Object();
            newPos.left = c.left + 100;
            newPos.top = c.top + 100;
            return newPos;
        });
    });
});

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容