Egret社区

源码分享_麻将逻辑代码

2017-4-14 00:35
1650343
本帖最后由 nodep 于 2017-4-18 21:42 编辑

简单棋牌编写思路,如果没思路最好别拿别人代码,得不偿失源码在楼下

mahjong_demo.zip

773.92 KB, 阅读权限: 10, 下载次数: 763, 下载积分: 银子 -1

售价: 1 银子  [记录]

分享到 :
11 人收藏

43 个回复

正序浏览
nodep  渐入佳境 | 2017-4-14 16:24:44
如图所示,实现了主逻辑流程
在LogicDemo里可配置自己的初始牌
另外碰可以照着杠抄过来,因为我自己并不做H5工作,还有自己的东西要写。棋牌的demo就到这里了。斗地主什么的都和这个差不太多。
胡牌的逻辑:
首先在加上(当前打出来的或自己摸起来的情况下)。不能有独立存在的牌,这个是思路起点。接下来可以用递归组合的方式组合起来。只要是
没有独立的牌,并且对子不超过1个(当然有七对的逻辑),所以每个地方的胡牌不一样,这个还是要自己写了。过周末了,太懒,不想写了。

参考图

参考图
nodep  渐入佳境 | 2017-4-14 17:19:28

主要目录结构,比较粗暴

主要目录结构,比较粗暴

[mw_shl_code=cpp,true]
/**逻辑 这个是后端完成的,这里模拟后端和延迟通信*/
class LogicDemo {

        private _cards: Array<CardData>;
        public __dealRing:number = 0;
        private _getted:boolean = true;
        private static _ins: LogicDemo;

        public aiCard:CardData;
        //---在这里配置你想摸到的牌,方便测试---
        private _initSelfCardTypes:number[] = [1,1,1,1,2,2,2,2];
        private _initSelfCardNum:number[] = [1,1,1,1,2,2,2,2];

        public constructor() {
        }

        public static get ins(): LogicDemo {
                if (!LogicDemo._ins)
                        LogicDemo._ins = new LogicDemo();
                return LogicDemo._ins;
        }

        /**发牌 */
        public dealCards(): void {
                SelfCardGroup.getIns().setInfo("正在发牌...");
                this.__dealRing = 0;
                this.createCards();//创建
                this.shuffle();//洗牌
                this.deal();
        }

        //我的回合结束
        public optionEnd():void
        {
                this._getted = false;
                this.__dealRing = 0;
                this.continueGame();
        }

        //继续
        public goOn():void
        {
                this.continueGame();
        }

        /**发一张牌给我,从开头 */
        public shiftOne():void
        {
                SelfCardGroup.getIns().addCard(this._cards.shift(),false);
                SelfCardGroup.getIns().gogo();
        }

        /**开始游戏 */
        private continueGame():void
        {
                if(this._getted)//等待玩家出牌
                {
                        SelfCardGroup.getIns().gogo();
                        return;
                }
                else
                {
                        this.__dealRing++;
                        if(this.__dealRing%4!=0)//给计算机发牌
                        {
                                this.jump();
                        }
                        else//给自己发牌
                        {
                                DelayCall.call(1000,this.dealSelf,this);
                        }
                }
        }

        /**计算机出牌,僵尸摸什么打什么 */
        private jump():void
        {
                this.aiCard = this._cards.pop();
                SelfCardGroup.getIns().looklook();
        }

        /**给自己发一张牌 */
        private dealSelf():void
        {
                //玩家得到一张牌后等待玩家操作
                this._getted = true;
                SelfCardGroup.getIns().addCard(this._cards.pop(),false);
        }

        /**开始发牌逻辑 */
        private deal():void
        {
                if(this.__dealRing<3)//给所有人发牌,一次发4张
                {
                        //给自己发一张,其他人直接丢掉(测试用)
                        SelfCardGroup.getIns().addCard(this._cards.pop(),true);
                        SelfCardGroup.getIns().addCard(this._cards.pop(),true);
                        SelfCardGroup.getIns().addCard(this._cards.pop(),true);
                        SelfCardGroup.getIns().addCard(this._cards.pop(),true);
                        this._cards.splice(this._cards.length-12,12);
                        DelayCall.call(500,this.deal,this);
                }
                else//给自己补发一张
                {
                        this._getted = true;
                        this.__dealRing = 0;
                        SelfCardGroup.getIns().addCard(this._cards.pop(),true);
                        this._cards.pop();
                        this._cards.pop();
                        this._cards.pop();
                        SelfCardGroup.getIns().addCard(this._cards.pop(),true);
                        SelfCardGroup.getIns().sortCards(1000);
                        this.continueGame();
                        return;
                }
                this.__dealRing++;
        }

        //创建108
        private createCards(): void {
                this._cards = new Array<CardData>();
                //108张,如果要玩东南风需要扩展.对应筒条万
                for (var i: number = 1; i <= 3; i++) {
                        for (var c: number = 1; c <= 9; c++) {
                                this._cards.push(new CardData(i, c));
                                this._cards.push(new CardData(i, c));
                                this._cards.push(new CardData(i, c));
                                this._cards.push(new CardData(i, c));
                        }
                }
        }

        private _hzList:number[] = [];

        /**洗牌 */
        private shuffle():void{
                this._hzList = [];
                var cards:Array<CardData> = new Array<CardData>();
                var key:any;
                var card:CardData;
                for(key in this._cards)
                {
                        card = this._cards[key];
                        cards.splice(Math.floor(cards.length*Math.random()),0,card);
                }
                //----------在这里洗盒子-----------洗前12个就好了
                var insertIndex:number = 0;
                for(var i:number=0;i<this._initSelfCardTypes.length;i++)
                {
                        var insertCard:CardData = this.getChildBy(cards,this._initSelfCardTypes,this._initSelfCardNum);
                        this._hzList.push(insertCard.id);
                        if(insertCard==null)
                                console.log("异常");
                        cards.splice(cards.indexOf(insertCard),1);
                        cards.splice(cards.length-insertIndex,0,insertCard)
                        insertIndex++;
                        if(insertIndex%4==0)
                                insertIndex+=12;
                }
                this._cards = cards;
        }

        /**取 */
        private getChildBy(from:Array<CardData>,type:number,num:number):CardData
        {
                var key:any;
                var dd:CardData;
                for(key in from)
                {
                        dd = from[key];
                        if(dd.cType == type && dd.cNum == num && this._hzList.indexOf(dd.id)<0)
                                return dd;
                }
                return null;
        }
}[/mw_shl_code]
[mw_shl_code=cpp,true]
/**自己的牌组显示对象 */
class SelfCardGroup extends egret.DisplayObjectContainer {

        private _cards: Array<CardData> = new Array<CardData>();//手上的牌
        private _deskCards: Array<CardData> = new Array<CardData>();//碰和杠的牌

        private _cardBox: HBox;
        private _deskBox: HBox;
        private _focusCard: CardSprite;
        private _debugInfo: egret.TextField;
        private _focusType: string = "";
        private _cardKey: string = "";
        private _gangIndex: number = 0;
        private _gangArray: string[] = [];

        /**自己的牌面显示对象只会有一个 */
        private static _ins: SelfCardGroup;

        /**私有掉构造 */
        private constructor() {
                super();
                this._cardBox = new HBox();
                this._cardBox.touchEnabled = true;
                this.addChild(this._cardBox);
                this._deskBox = new HBox();
                this.addChild(this._deskBox);
                this.addChild(OptionBar.getIns());
                this._debugInfo = new egret.TextField();
                this._debugInfo.size = 30;
                this.addChild(this._debugInfo);
        }

        public static getIns(): SelfCardGroup {
                if (!SelfCardGroup._ins)
                        SelfCardGroup._ins = new SelfCardGroup();
                return SelfCardGroup._ins;
        }

        public setInfo(str: string): void {
                this._debugInfo.text = str;
                this._debugInfo.x = (this.stage.stageWidth - this._debugInfo.textWidth) / 2;
                this._debugInfo.y = 10;
        }

        /**得到一张牌 */
        public addCard(cd: CardData, isDeal: boolean = false): void {
                var card: CardSprite;
                if (isDeal)//如果是发牌
                {
                        card = new CardSprite(-1, cd);
                        card.delayFace();
                }
                else//如果是摸牌
                {
                        card = new CardSprite(1, cd);
                        this.gogo();
                }
                this._cards.push(cd);
                this._cardBox.addEle(card);
                this.resize();
        }

        public resize(): void {
                this._cardBox.y = this.stage.stageHeight - this._cardBox.height;
                this._cardBox.x = (this.stage.stageWidth - this._cardBox.width) / 2;
                this._deskBox.x = 10;
                this._deskBox.y = this.stage.stageHeight - 400;
                OptionBar.getIns().x = this.stage.stageWidth - OptionBar.getIns().width;
                OptionBar.getIns().y = this.stage.stageHeight - 400;
                this._debugInfo.x = (this.stage.stageWidth - this._debugInfo.textWidth) / 2;
                this._debugInfo.y = 10;
        }

        /**make your choose */
        public gogo(): void {
                this._focusType = "";//重置当前操作类型
                SelfCardGroup.getIns().setInfo("该你出牌...");
                this._cardBox.addEventListener(egret.TouchEvent.TOUCH_TAP, this.tabHandler, this)
                this.checkOpt("put");
        }

        /**do what? */
        public looklook(): void {
                this.setInfo("【" + LogicDemo.ins.__dealRing + "】出牌=" + CardSprite.getTxt(LogicDemo.ins.aiCard) + " 你要怎么操作?");
                OptionBar.getIns().changeBtnState("过", true);
                //如果有其他可操作的,放开确认
                this.checkOpt("turn");
        }

        /**点击事件 */
        private tabHandler(evt: egret.TouchEvent): void {
                this._focusType = "";//重置操作类型
                if (typeof (evt.target) != "object")
                        return;
                var cCount: number = this._cardBox.numChildren;
                for (var i: number = 0; i < cCount; i++)
                        this._cardBox.getChildAt(i).y = 0;
                var target: CardSprite = evt.target as CardSprite;
                if (this._focusCard == target) {
                        this._focusCard = null;
                        this.checkOpt("put");
                        return;
                }
                else {
                        this._focusCard = target;
                        this._focusCard.y = -20;
                        this.checkOpt("put");
                }
        }

        /**检查当前可操作项目,自己的出牌环节 */
        public checkOpt(t: string): void {
                if (t == "put")//检查出牌
                {
                        //检查自摸
                        //检查暗杠,检查明杠
                        OptionBar.getIns().changeBtnState("杠", this.checkGang());
                        //检查出牌和确认
                        OptionBar.getIns().changeBtnState("确认", true);
                        //这里不能过牌
                        OptionBar.getIns().changeBtnState("过", false);
                }
                else if (t == "turn")//检查所有
                {
                        //检查胡牌
                        //检查明杠
                        var gangFlag: boolean = this.checkGang(LogicDemo.ins.aiCard);
                        OptionBar.getIns().changeBtnState("杠", gangFlag);
                        //检查碰牌
                        //如果有其他可操作项,这里就有确认
                        OptionBar.getIns().changeBtnState("确认", gangFlag);
                        //这里可以过
                        OptionBar.getIns().changeBtnState("过", true);
                }
        }

        /**排序 */
        public sortCards(delayTime: number = 0): void {
                if (delayTime > 0) {
                        DelayCall.call(delayTime, this.sortCards, this);
                        return;
                }
                //------将牌进行排序-------
                this._cards.sort(function (a: CardData, b: CardData): number {
                        if (a.cType * 10 + a.cNum > b.cType * 10 + b.cNum)
                                return 1;
                        return -1;
                });
                for (var i: number = 0; i < this._cards.length; i++) {
                        (this._cardBox.getChildAt(i) as CardSprite).setData(this._cards);
                }
        }

        /**操作来了 */
        public optionHandler(type: string): void {
                switch (type) {
                        case "确认": this.option_queren();
                                break;
                        case "过":
                                this.clearOption();
                                LogicDemo.ins.goOn();
                                break;
                        case "杠":
                                this._focusType = "杠";
                                this.changeGang();
                                break;
                        default:
                                console.log("还未处理这个类型" + type);
                                break;
                }
        }

        private clearOption(): void {
                OptionBar.getIns().changeBtnState("过", false);
                OptionBar.getIns().changeBtnState("确认", false);
                OptionBar.getIns().changeBtnState("杠", false);
                OptionBar.getIns().changeBtnState("胡", false);
                OptionBar.getIns().changeBtnState("碰", false);
        }

        private doEnd(): void {
                this._cardBox.removeEventListener(egret.TouchEvent.TOUCH_TAP, this.tabHandler, this)
                this.clearOption();
                LogicDemo.ins.optionEnd();
        }

        /**确认的操作响应 */
        private option_queren(): void {
                if (this._focusType == "")//出牌
                {
                        if (this._focusCard == null)
                                this.setInfo("点击一张你要出的牌");
                        else {
                                var delIndex: number = this._cards.indexOf(this._focusCard.data);
                                this._cardBox.removeEle(this._focusCard);
                                this._cards.splice(delIndex, 1);
                                this.doEnd();
                                this.sortCards(0);
                        }
                }
                else {
                        switch (this._focusType) {
                                case "杠":
                                        this.removeCardToDesk(this._cardKey, 4);
                                        this.clearOption();
                                        LogicDemo.ins.shiftOne();
                                        break;
                        }
                }
        }

        //-------------------------逻辑部分粗暴解决------------------------
        //为了更好的性能和维护性,应该在玩家牌组发生变化的时候就计算好哪些是可以杠,哪些是可以碰的。这里懒的改了,随手写

        /**显示多少个牌 */
        private showKeys(key: string, count: number): void {
                var cCount: number = this._cardBox.numChildren;
                var i: number = 0;
                for (i = 0; i < cCount; i++)
                        this._cardBox.getChildAt(i).y = 0;
                var cs: CardSprite;
                var cc: number = 0;
                for (i = 0; i < cCount; i++) {
                        cs = this._cardBox.getChildAt(i) as CardSprite;
                        if (cs.data.key != key)
                                continue;
                        cs.y = -20;
                        cc++;
                        if (cc >= count)
                                return;
                }

        }

        /**移动牌到桌子 */
        private removeCardToDesk(key: string, count: number): void {
                var cCount: number = this._cardBox.numChildren;
                var i: number = 0;
                for (i = 0; i < cCount; i++)
                        this._cardBox.getChildAt(i).y = 0;
                var cc: number = 0;
                if (LogicDemo.ins.aiCard && LogicDemo.ins.aiCard.key == key) {
                        cc++;
                        this._deskCards.push(LogicDemo.ins.aiCard);
                        LogicDemo.ins.aiCard = null;
                }
                var keyc: any;
                var cd: CardData;
                for (keyc in this._cards) {
                        if (cc >= count)
                                break;
                        cd = this._cards[keyc];
                        if (cd.key == key) {
                                cc++;
                                this._deskCards.push(cd);
                        }
                }
                for (keyc in this._deskCards) {
                        cd = this._deskCards[keyc];
                        i = this._cards.indexOf(cd);
                        if (i >= 0)
                        {
                                this._cards.splice(i, 1);
                                this.removeCardByID(cd.id);
                        }
                }
                this.sortCards(0);
                var index:number = 0;
                if(count==4)
                        count=1;
                while(this._deskBox.numChildren<this._deskCards.length)
                {
                        var putIndex:number = this._deskBox.numChildren;
                        var dsc:CardSprite = new CardSprite(index++<count?1:-1,this._deskCards[putIndex]);
                        this._deskBox.addEle(dsc);
                }
        }

        /**移除显示 */
        private removeCardByID(cid: number): void {
                var cCount: number = this._cardBox.numChildren;
                var i: number = 0;
                for (i = 0; i < cCount; i++) {
                        var cs:CardSprite = this._cardBox.getChildAt(i) as CardSprite;
                        if(cs.data.id == cid)
                        {
                                this._cardBox.removeEle(cs,false);
                                break;
                        }
                }
        }


        private addCardToMap(map: Map<string, number>, c: CardData, checkHas: boolean = false): void {
                if (map.get(c.key) == null && !checkHas)
                        map.set(c.key, 1);
                else
                        map.set(c.key, map.get(c.key) + 1);
        }

        /**
         * 明暗杠检查
         * 重点:无论是明杠还是按杠,首先必须受伤要有这个牌.
         */
        private checkGang(fromCard: CardData = null): boolean {
                var oc: CardData = fromCard;
                this._gangArray = [];
                this._gangIndex = 0;
                var handMap: Map<string, number> = new Map<string, number>();
                var keys: string[] = [];
                if (fromCard != null)//说明是杠他人的牌,只算手牌
                {
                        this.addCardToMap(handMap, fromCard);
                        keys.push(fromCard.key);
                }
                var key: any;
                for (key in this._cards) {
                        fromCard = this._cards[key];
                        this.addCardToMap(handMap, fromCard, oc != null);
                        if (keys.indexOf(fromCard.key) < 0)
                                keys.push(fromCard.key);
                }
                for (key in this._deskCards) {
                        fromCard = this._deskCards[key];
                        this.addCardToMap(handMap, fromCard, true);
                }
                for (key in keys) {
                        if (handMap.get(keys[key]) >= 4)
                                this._gangArray.push(keys[key]);
                }
                return this._gangArray.length > 0;
        }

        /**更换杠的组合 */
        private changeGang(): void {
                this._cardKey = this._gangArray[this._gangIndex];
                this.showKeys(this._cardKey, 4);
                this._gangIndex++;
                if (this._gangIndex >= this._gangArray.length)
                        this._gangIndex = 0;
        }
}[/mw_shl_code]
大概结构和最主要的两个类,都是比较粗暴的解决了。
从main.entergame开始,这里没有改框架生成的代码。

逻辑代码的衔接主要在
SelfCardGroup的checkOpt();
"put" = 出牌
"turn" = 等待过牌

optionBar中用了中文,主要是为了方便阅读。
CardType里1-3对应筒条万
我想做游戏  登堂入室 | 2019-7-5 15:53:03
nodep 发表于 2017-4-14 16:24
如图所示,实现了主逻辑流程
在LogicDemo里可配置自己的初始牌
另外碰可以照着杠抄过来,因为我自己并不做H5 ...

66666
hhtv3s1994  登堂入室 | 2018-9-6 20:53:12
我想学棋牌麻将
白衣  初学乍练 | 2018-4-6 18:38:12
下载来看看
zjjxxhn  初学乍练 | 2017-12-26 16:41:14
本帖最后由 zjjxxhn 于 2017-12-28 10:42 编辑

需要真实姓名验证,
nodep  渐入佳境 | 2017-12-26 14:38:49
zjjxxhn 发表于 2017-12-26 10:08
好,学习一下。。。方便认识一下吗,我还没有加好友权限,方便给我单独给个联系方式把 ...

QQ623440028
zjjxxhn  初学乍练 | 2017-12-26 10:08:01
好,学习一下。。。方便认识一下吗,我还没有加好友权限,方便给我单独给个联系方式把
脸大不羁  登堂入室 | 2017-11-22 19:59:29
请问,如果用egret2d来做四人麻将,其他三人的牌的展示怎么实现?(看上去是立体的且有角度的)
路迷在海  登堂入室 | 2017-10-26 15:29:41
学习学习,正在写斗地主
13719965417  初学乍练 | 2017-9-30 12:08:00
大佬关于牌的显示是怎么构建?就是只能自己看到牌,除非自己摊牌,还有就是每个坐标问题,当进行网络在线对战的时候,如何设计坐标
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|京网文[2014]0791-191号|京ICP证150115号|Egret社区 ( 京ICP备14025619号 )

Powered by Discuz! X3.4 © 2001-2019 Comsenz Inc.

返回顶部