斗地主游戏文档

1.体系结构图

斗地主游戏文档_第1张图片
体系结构图.png

2.逻辑流程图

2.1简易流程图

斗地主游戏文档_第2张图片
逻辑流程图.png

2.2详细流程图

斗地主游戏文档_第3张图片
详细逻辑流程图.png

3.服务器-客户端通讯图

斗地主游戏文档_第4张图片
sc通讯图.png

4.数据结构

4.1牌型

斗地主游戏文档_第5张图片
Paste_Image.png
  • 一副牌,共54张,由左至右相应的index从0开始排开;
  • 牌型:
    单牌(ONE):任意一张单牌(3 < 4 <… < K< A < 2 < 小王<大王)。
    对子(TWO):任意两张点数相同的牌,如:66。
    三头(THREE):任意三张点数相同的牌,如666。
    连三(THREE_2): 二个连续三张牌,如:333444
    单顺(STRAIGHT): 任意五张或五张以上点数相连的牌,如:45678或78910JQK。不包括 2和双王。
    双顺(TWO_2): 三对或更多的连续对牌
    三顺(THREE_3): 三对或更多连续三张牌,如:333444555
    炸弹(FOUR):任意四张点数相同的牌,如:6666

4.2牌型比较

  • 大小顺序:3,4,5,6,7,8,9,10,J,Q,K,A,2,大王,小王。
  • 根据相应的index转为对应大小的value,3-K分别对应3-13,A:14,2:15,小王:16 , 大王:17
  • 除炸弹以外,普通牌型不允许对压,相同牌型下比它大的能对压。

4.3压牌逻辑

斗地主游戏文档_第6张图片
压牌逻辑.png

5.页面展示

5.1开始游戏

斗地主游戏文档_第7张图片
开始游戏.PNG

5.2等待页面

斗地主游戏文档_第8张图片
等待.PNG

5.3发牌页面

斗地主游戏文档_第9张图片
发牌页面.PNG

6代码展示

6.1页面渲染

//等待页面
var htmlWait = "

Waiting....

正在为你寻找小伙伴
"; //发牌页面 var htmlPoker="
"; //登录页面 var htmlStart=""; //忙碌页面 var htmlCrowded="

Cowded....

房间好挤呀,你暂时进不来
";

6.2结构定义

  • 用户对象
//状态定义
var INIT="INIT";//初始化
var WAITING="WAITING";//等待
var DISCARD="DISCARD";//发牌
var GAMEOVER="GAMEOVER";//游戏结束
var pkObj = {
    data:{
        status:INIT,
        count:27,
        pokers:[]
    },
    from:id,
    to: fid,
    success:0,
    init:function (){
        if(pkObj.data.status===INIT){
            $("#login").click(doInit);
        }
        socketInit();
    }
};
  • 牌对象
var ONE = "ONE";
var TWO = "TWO";
var TWO_2 = "TWO_2";
var THREE = "THREE";
var THREE_2 = "THREE_2";
var THREE_3 = "THREE_3";
var FOUR = "FOUR";
var STRAIGHT = "STRAIGHT";
var ERROR = "ERROR";
var KING = "KING";
 var poker= {
        type: type,                        //类型
        val: m,                            //大小
        length: pokerList.length  //张数
    };

6.3消息模型

  • 服务器端
io.on('connection', function(socket){
//添加用户
socket.on('add user', function (obj) {
    count++;
    //玩家一加入
     if(count===1){
        socket.join(obj.from);
        first=obj;
        first.authority=true;
     }
  //玩家二加入
    else if(count===2){
        socket.join(obj.from);
        second=obj;
        //洗牌
        var res=shuffle();
        first.data.pokers=res.poker1;
        second.data.pokers=res.poker2;
        first.to=second.from;
        second.to=first.from;
        //用户状态改变由WAITING到DISCARD发牌
        first.data.status=DISCARD;
        second.data.status=DISCARD;
        //发送发牌事件
        io.to(first.from).emit("start poker", first);
        io.to(second.from).emit("start poker", second);
        }
      //玩家三登入
        else{
            socket.join(obj.from);
            other=obj;
             io.to(other.from).emit("crowded", other);
        }
  }
//监听discard事件,当一方的牌数剩余为0,发送游戏结束信号
socket.on('discard',function(data,sendMessage){
    if(data.data.count===0){
        io.to(data.from).emit("game over", 1);
        io.to(data.to).emit("game over",2 );
    }
    else{
      //当牌还有剩余时,向对手发送接收牌的信号
        io.to(data.to).emit("receive poker", sendMessage,data.data.count);
    }
  })
  //监听abandon事件,当有一方放弃游戏,发送游戏结束信号
  socket.on('abandon',function(data){
      io.to(data.from).emit("game over", 3);
      io.to(data.to).emit("game over",4);
    })
  })
  • 客户端
function socketInit() {
    //发牌
    socket.on('start poker', function (data) {
        doDiscard(data);
    });
  //接收对方的牌
    socket.on('receive poker',function (data,count) {
        doReceive(data,count);
    });
  //拥挤
    socket.on('crowded',function () {
        doCrowded();
    });
  //游戏结束
    socket.on('game over',function (data) {
        //自己获胜
        if(data===1)
        {
            alert("you win!");
        }
      //对方获胜
        else if(data===2){
            alert("you lose!");
        }
        //自己放弃
        else if(data===3){
            alert("你放弃啦!");
            $(".wrapper").html("");
           //回到初始页面
            $(".wrapper").append(htmlStart);
            $("#login").click(doInit);
            pkObj.data.status=INIT;
        }
        else{
            alert("对方落荒而逃,恭喜你,不战而胜!");
        }
    })
}  
                            

6.4函数介绍

服务端
  • 洗牌函数
//洗牌
function shuffle() {
  var pokers = new Array();
  for(var i = 0; i < 54; i++) {
    pokers[i]=i;
  }
  for (var i = 0; i < 54; i++) {
    var rd=parseInt(Math.random()*54);
    var b=pokers[i] ;
    pokers[i]= pokers[rd];
    pokers[rd]=b;
}
   var poker1 = [];
   var poker2 = [];
   for(var i = 0; i < 54; i++) {
    if(i<27)
        poker1[i]=pokers[i];
     else{
        poker2[i-27]=pokers[i];
    }
   }
   sort(poker1);
   sort(poker2);
  result = {
    poker1: poker1,
    poker2: poker2
  };
  return result;
}
//排序
function sort(pokers){
    var i=27;
    var temp;
    while (i > 0) {
    for (var j = 0; j < i - 1; j++) {
        if (((pokers[j]+11)%13> (pokers[j + 1]+11)%13)&&(pokers[j + 1]!==52||pokers[j + 1]!==53)) {
            temp = pokers[j];
            pokers[j] = pokers[j + 1];
            pokers[j + 1] = temp;}
        //小王
        if(pokers[j]===53){
            temp = pokers[j];
            pokers[j] = pokers[26];
            pokers[26] = temp;}
        //大王
        if(pokers[j]===52){
            temp = pokers[j];
            pokers[j] =pokers[j+1];
            pokers[j+1] = temp;}
                   }
                    i--;
         }
}
客户端
  • 发牌
function doDiscard(data) {
    pkObj=data;
    $(".wrapper").html("");
    $(".wrapper").append(htmlPoker);
    //自己的牌
    yourPoker();
  //对方的牌
    myPoker(pkObj.data);
    $(".poker").click(function(){
        if($(this).hasClass("select")){
            $(this).removeClass("select");
            $(this).animate({top:"+=50px"});
        }
        else{
            $(this).addClass("select");
            $(this).animate({top:"-=50px"});
        }
    });
    //发牌
    $(".confirm").click(function(){
        //得到对方发来的牌
        var oppo_pokerList=new Array();
        if($(".display").children() !== null){
            $(".display").children().each(function(){
                oppo_pokerList.push(parseInt($(this).attr("data-value")));});
        }

        //得到自己的牌
        var pokerList=new Array();
        for(var i=0;i<27;i++){
            var index=".choose .poker"+i;
            if($(index).hasClass('select')){
                $(index).html();
                pokerList.push(parseInt($(index).attr("data-value")));
            }
        }
        if(getPokerType(pokerList).type===ERROR){
            console.log("error");
            alert("发的牌不和标准");
            doCancel();
        }
        //对方没有牌即自己首发or对方放弃 自己没有牌即表示放弃
        else if(oppo_pokerList.length===0||pokerList.length===0){
            doConfirm(pkObj);
        }
         //自己牌合乎标准
         else if(comparePoker(pokerList,oppo_pokerList)) {
            doConfirm(pkObj);
        }
        else{
            alert("发的牌不和标准");
            doCancel();
        }
    });
    //取消
    $(".cancel").click(function(){
        console.log("cancel");
        doCancel();
    });
    //不出
    $(".no").click(function(){
        $(".display .poker").remove();
        var sendMessage=$(".display").html();
        socket.emit('discard', pkObj, sendMessage);
        doCancel();
    });
    //退出游戏
        $(".abandon").click(function(){
        socket.emit('abandon', pkObj);
    })
}
  • 出牌
function doConfirm(pkObj) {
    var count=0;
    $(".display .poker").remove();
    for(var i=0;i<27;i++){
        var index=".poker"+i;
        if($(index).hasClass('select')){
            $(index).html();
            $(".display").append($(index));
            count++;
        }
    }
    var sendMessage=$(".display").html();
    pkObj.data.count-=count;
    socket.emit('discard', pkObj, sendMessage);
    $(".confirm").hide();
    $(".no").hide();
}
  • 放弃出牌
function doCancel() {
    for(var i=0;i<13;i++){
        var index=".choose .poker"+i;
        if($(index).hasClass('select')){
            $(index).removeClass('select');
            $(index).animate({top:"+=50px"});
        }
    }
}
  • 牌面大小转换
function myPoker(data) {
    for(var i=0;i<27;i++){
        var x=data.pokers[i]%13*(-90);
        var y=parseInt(data.pokers[i]/13)*(-120);
        var left=x+"px";
        var top=y+"px";
        var count;
        //大王
        if(data.pokers[i]===52)
            count=17;
        //小王
        else if(data.pokers[i]===53)
            count=16;
        //A
        else if((data.pokers[i]+11)%13===11){
            count=14;
        }
        //2
        else if((data.pokers[i]+11)%13===12){
            count=15;
        }
        else {
            count=(data.pokers[i])%13+1;
        }
        var pokeri="poker"+i;
        var html = $("").addClass(pokeri).attr("data-value", count);
        html.css({"background-position":left+" "+top});
        $(".pokers").append(html);
    }
}
  • 接收牌
function doReceive(data,after) {
    $(".confirm").show();
    $(".no").show();
     var before= $(".oppo-pokers").children().length;
    for(var i=before;i>after;i--){
        $(".oppo-pokers").children('.oppo-poker:last').remove();
    }
    if($(".display").children() != null){
        $(".display .poker").remove();
    }
    $(".display").append(data);
}
  • 牌型状态机
function typeState(type, n, m) {
    switch (type) {
        //单
        case ONE:
            if(n == m) {
                type = TWO;
            } else if(n == m +1 && m == 16) {
                type = KING;
            } else if(n == m + 1){
                type = STRAIGHT;
            } else {
                type = ERROR;
            }
            break;
        //对
        case TWO:
            if(n == m) {
                type = THREE;
            } else if(n == m + 1){
                type = TWO_2;
            } else {
                type = ERROR;
            }
            break;
        case TWO_2:
            if(n == m) {
                type = TWO;
            } else {
                type = ERROR;
            }
            break;
        case THREE:
            if(n == m) {
                type = FOUR;
            } else if(n == m + 1){
                type = THREE_2;
            } else {
                type = ERROR;
            }
            break;
        case THREE_2:
            if(n == m) {
                type = THREE_3;
            } else {
                type = ERROR;
            }
            break;
        case THREE_3:
            if(n == m) {
                type = THREE;
            } else {
                type = ERROR;
            }
            break;
        case STRAIGHT:
            if(n == m + 1) {
                type = STRAIGHT;
            } else {
                type = ERROR;
            }
            break;
        default:
            break
    }
    return type;
}
  • 牌型获取
function getPokerType(pokerList) {
    var type = ONE;
    var n, m;
    if(pokerList.length===1){
        m=pokerList[0];
    }
    else {
        for (var i = 0; i < pokerList.length; i++) {
            n = pokerList[i];
            m = pokerList[i + 1];
            type = typeState(type, n, m);
        }
        if(type == TWO_2 || type == THREE_2 || type == THREE_3 || (type == STRAIGHT && pokerList.length < 5)) {
            type = ERROR;
        }
    }

    var poker= {
        type: type,
        val: m,
        length: pokerList.length
    };
    return poker;
}
  • 牌型大小比较
function comparePoker(pokerList,oppo_pokerList) {
    var flag= false;
    var data1 = getPokerType(oppo_pokerList); //对方的牌类型
    var data2 = getPokerType(pokerList);  //我的牌类型
    if((data1.type == data2.type && (data1.length == data2.length) && pokerList[0] > oppo_pokerList[0]) || (data1.type != FOUR && data2.type == FOUR) || (data2.type == KING)) {
        flag= true;
    }
    //flag为true可出牌,否则不能出牌
    return flag;
}

你可能感兴趣的