Beispiel #1
0
        /// <summary>
        /// 番役的计算
        /// (根据调用_IsHu函数后的huCard计算,请勿在这之前调用)
        /// </summary>
        /// <param name="Status">是否考虑状况役(当听牌判役时不考虑)</param>
        /// <param name="TankiOrW13">是否处于单骑听牌或13面听牌状态</param>
        private List <MahjongYaku> calcYaku(List <HuCard> huCard, bool Status, bool TankiOrW13)
        {
            // 为避免役型冲突设立的状态布尔
            bool isFuru      = false; // 副露
            bool isChitoi    = false; // 七对:可和断幺九、混一色、清一色、混老头,覆盖一杯口,被二杯口覆盖
            bool isYakuman   = false; // 已经有役满以上的役种,不再累加役满一下的役种
            bool isKong4     = false; // 四杠子:不再计算四暗刻、四暗刻单骑和应援四暗刻
            bool isDaisangen = false; // 三团体推:和应援推冲突
            bool isGroup     = false; // 团单推/纯正单推:和混单推冲突
            bool isLeader    = false; // 队长同刻:和应援同组冲突
            bool isNipeko    = false; // 二杯口:和一杯口冲突

            List <MahjongYaku> yakus = new List <MahjongYaku>();

            // 状况役:与手牌无关,与场上状况有关的役
            // 行为役:立直 門前清自摸和 ダブル立直
            // 偶然役:一発 搶槓 嶺上開花 海底摸月 河底撈魚 ダブル立直 天和 地和
            // 特殊役:流し満貫
            // 加成役:单骑 十三面
            // 手役: 与手牌有关的役

            // 加番(累加):宝牌 赤宝牌 里宝牌

            // 检查特殊役种 十三幺
            if (huCard.First().type == HuCardType.Yao13)
            {
                // 确定十三幺性质(十三面/正常十三幺)
                if (TankiOrW13)
                {
                    yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.DDWait13]);
                }
                else
                {
                    yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.DD]);
                }

                // 返回
                return(yakus);
            }
            else
            {
                // 检查特殊役种 七对子
                IEnumerable <HuCard> query = from hu in huCard where hu.type == HuCardType.Finch select hu;
                IEnumerable <HuCard> subquery;
                if (query.Count() == 7)
                {
                    // 确认含有七对子
                    isChitoi = true;                                                        // 设置防止其它役冲突
                    yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Chitoi]); // 加入役
                }

                // 确定副露状态
                query = from hu in huCard where hu.furu == true select hu;
                if (query.Count() > 0)
                {
                    isFuru = true; // 有副露行为,是副露状态
                }
                else
                {
                    isFuru = false; // 没有副露行为,是门前清状态
                }

                // 由高到低确定番役
                // 计算刻子数
                query = from hu in huCard where hu.type == HuCardType.PongKong select hu;
                int pongkong_cnt = query.Count();

                // 役满以上
                // 非门前清役种
                if (pongkong_cnt == 4)
                {
                    // 多数刻子
                    // 応援推し
                    query = from hu in huCard
                            where hu.cards.First().type == MahjongCardType.Assist
                            group hu by hu.cards.First().name into gp
                            select gp.First();

                    if (query.Count() == 5) //包含四个刻子和一个雀头
                    {
                        isYakuman = true;
                        yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Ouen]);
                    }

                    // 四杠子
                    query = from hu in huCard where hu.cards.Count == 4 select hu;
                    if (query.Count() == 4)
                    {
                        isKong4   = true;
                        isYakuman = true;
                        yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Kong4]);
                    }
                }
                else if (pongkong_cnt == 3)
                {
                    // 没有应援推的情况下
                    if (!isDaisangen)
                    {
                        // 三刻子
                        // 三团体推
                        query = from hu in huCard where (hu.cards.First().type == MahjongCardType.Group) && (hu.type == HuCardType.PongKong) select hu;
                        if (query.Count() == 3)
                        {
                            isYakuman = true;
                            yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Daisangen]);
                        }
                    }
                }

                // 门前清役种
                if (!isFuru)
                {
                    if (!isKong4)
                    {
                        // 在没有四杠子的情况下
                        if (pongkong_cnt == 4)
                        {
                            // 多数刻子
                            // 四暗刻(包括四暗刻,応援四暗刻)
                            // 先查询带条件的应援四暗刻
                            query = from hu in huCard where (hu.cards.First().type == MahjongCardType.Assist) && (hu.type == HuCardType.PongKong) select hu;
                            if (query.Count() == 4)
                            {
                                isYakuman = true;
                                yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Anko4Ouen]); // 应援四暗刻
                            }
                            else
                            {
                                isYakuman = true;
                                if (TankiOrW13)
                                {
                                    yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Anko4Wait1]); // 四暗刻单骑
                                }
                                else
                                {
                                    yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Anko4]); // 四暗刻
                                }
                            }
                        }
                    }
                }

                // 役满以下
                if (!isYakuman)
                {
                    // 满贯
                    if (pongkong_cnt == 4)
                    {
                        // 多数刻子
                        // 全力应援
                        // 四组应援角色刻子
                        query = from hu in huCard
                                where (hu.cards.First().type == MahjongCardType.Assist) && (hu.type == HuCardType.PongKong)
                                select hu;
                        if (query.Count() == 4)
                        {
                            // 角色雀头
                            query = from hu in huCard where hu.type == HuCardType.Finch select hu;
                            if (query.First().cards.First().type == MahjongCardType.Char)
                            {
                                yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Zenryoku]);
                            }
                        }
                    }
                    else
                    {
                        // 団体単推し
                        query = from hu in huCard
                                where hu.cards.First().type == MahjongCardType.Group
                                select hu;

                        // 一种团体
                        if (query.Count() == 1)
                        {
                            MahjongCardGroupType group_oshi = query.First().cards.First().group; // 记录团体
                            // 剩余的牌全部是同一团体的角色牌
                            query    = from hu in huCard where hu.cards.First().@group != group_oshi select hu;
                            subquery = from hu in huCard where hu.cards.First().type != MahjongCardType.Char select hu;

                            if ((query.Count() == 0) && (subquery.Count() == 1)) // 角色只有一种团体
                            {
                                isGroup = true;
                                yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Group]);
                            }
                        }
                    }

                    // 六番
                    // 纯正单推
                    query = from hu in huCard where hu.cards.First().type != MahjongCardType.Char select hu;
                    if (query.Count() == 0) // 只有角色牌
                    {
                        subquery = from hu in huCard group hu by hu.cards.First().@group into g select g.First();

                        if (subquery.Count() == 1)
                        {
                            isGroup = true;
                            yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Junsei]);
                        }
                    }

                    // 三番
                    if (pongkong_cnt == 3)
                    {
                        // 三刻子
                        // 队长同刻
                        query = from hu in huCard
                                where (hu.type == HuCardType.PongKong) &&
                                ((hu.cards.First().name == MahjongCardName.Honoka) ||
                                 (hu.cards.First().name == MahjongCardName.Chika) ||
                                 (hu.cards.First().name == MahjongCardName.Ayu))
                                select hu;

                        if (query.Count() == 3)
                        {
                            isLeader = true;
                            yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Leader]);
                        }

                        // 没有队长同刻的情况下
                        if (!isLeader)
                        {
                            //应援同组(A-RISE)
                            query = from hu in huCard
                                    where (hu.type == HuCardType.PongKong) &&
                                    ((hu.cards.First().name == MahjongCardName.Tsubasa) ||
                                     (hu.cards.First().name == MahjongCardName.Anju) ||
                                     (hu.cards.First().name == MahjongCardName.Erena))
                                    select hu;

                            if (query.Count() == 3)
                            {
                                yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Arise]);
                            }
                        }
                    }
                    else
                    {
                        if (!isFuru)
                        {
                            // 二杯口
                            query = from hu in huCard
                                    where (hu.type == HuCardType.GradeChi) || (hu.type == HuCardType.SquadChi)
                                    select hu;

                            if (query.Count() == 4)
                            {
                                // 至少有四组年级或小组的顺子
                                subquery = from hu in query
                                           group hu by hu.cards.First().name into g
                                           select g.First();

                                if (subquery.Count() == 2)
                                {
                                    isNipeko = true;

                                    // 只有两种顺子
                                    // 如果有七对子先删除七对子
                                    if (isChitoi)
                                    {
                                        for (int i = 0; i < yakus.Count; i++)
                                        {
                                            if (yakus[i].type == MahjongYakuType.Chitoi)
                                            {
                                                yakus.RemoveAt(i);
                                                break;
                                            }
                                        }
                                        isChitoi = false;
                                    }

                                    yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Nipeko]);
                                }
                            }
                        }
                    }

                    // 二番
                    if (pongkong_cnt == 4)
                    {
                        // 多数刻子
                        // 对对和
                        yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Toitoi]);
                    }
                    else if (pongkong_cnt == 3)
                    {
                        // 三刻子
                        // 三暗刻
                        if (!isFuru)
                        {
                            yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Anko3]);
                        }

                        // 三杠子
                        query = from hu in huCard
                                where (hu.type == HuCardType.PongKong) && (hu.cards.Count() == 4)
                                select hu;

                        if (query.Count() == 3)
                        {
                            yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Kong3]);
                        }
                    }
                    else
                    {
                        // 没有团单推或纯正单推
                        if (!isGroup)
                        {
                            // 混单推
                            query    = from hu in huCard where (hu.type == HuCardType.PongKong) && (hu.cards.First().type == MahjongCardType.Char) select hu;
                            subquery = from hu in query group hu by hu.cards.First().@group into g select g.First();

                            if (subquery.Count() == 1)
                            {
                                if ((from hu in huCard where (hu.type == HuCardType.Finch) select hu.cards.First()).First().type != MahjongCardType.Char)
                                {
                                    yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Honoshi]);
                                }
                            }
                        }

                        // 没有队长同刻的情况下
                        if (!isLeader)
                        {
                            //应援同组(Saint Snow)
                            query = from hu in huCard
                                    where (hu.type == HuCardType.PongKong) &&
                                    ((hu.cards.First().name == MahjongCardName.Seira) ||
                                     (hu.cards.First().name == MahjongCardName.Ria))
                                    select hu;

                            if (query.Count() == 2)
                            {
                                yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Saint]);
                            }
                        }

                        // 三团同年
                        query = from hu in huCard
                                where hu.type == HuCardType.GradeChi
                                group hu by hu.cards.First().@group into g
                                select g.First();

                        if (query.Count() == 3)
                        {
                            // 有三个团体都有
                            // 找到只有一组的团体,以该团体作为基准
                            query = from hu in huCard
                                    where hu.type == HuCardType.GradeChi
                                    group hu by hu.cards.First().@group into g
                                        where g.Count() == 1
                                    select g.First();

                            MahjongCardGroupType group = query.First().cards.First().group;
                            MahjongCardGradeType grade = query.First().cards.First().grade;
                            // 找出所有符合同年级的但非同组的,按组分组到不同的组中
                            query = from hu in huCard
                                    where (hu.type == HuCardType.GradeChi) && (hu.cards.First().grade == grade) &&
                                    (hu.cards.First().@group != @group)
                                    group hu by hu.cards.First().@group into g
                                    select g.First();

                            if (query.Count() == 2)
                            {
                                // 如果剩余两组都拥有同年级
                                yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.SameGrade]);
                            }
                        }
                    }

                    // 一番
                    // 角色纯
                    query = from hu in huCard
                            where (hu.cards.First().type == MahjongCardType.Char) || (hu.cards.First().type == MahjongCardType.Assist)
                            select hu;
                    if (query.Count() == 5)
                    {
                        yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Char]);
                    }

                    // 断幺九
                    bool danyau = true;
                    foreach (HuCard hu in huCard)
                    {
                        if ((hu.type == HuCardType.Finch) || (hu.type == HuCardType.PongKong))
                        {
                            if (hu.cards.First().yao9 == true)
                            {
                                danyau = false;
                                break;
                            }
                        }
                        else
                        {
                            foreach (MahjongCard card in hu.cards)
                            {
                                if (card.yao9 == true)
                                {
                                    danyau = false;
                                    break;
                                }
                            }
                        }
                    }

                    if (danyau)
                    {
                        yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Danyao]);
                    }

                    if ((!isFuru) && (!isNipeko))
                    {
                        // 一杯口
                        query = from hu in huCard
                                where (hu.type == HuCardType.GradeChi) || (hu.type == HuCardType.SquadChi)
                                select hu;

                        if (query.Count() >= 2)
                        {
                            // 至少有两组年级或小组的顺子
                            IEnumerable <int> subsubquery = from hu in query
                                                            group hu by hu.cards.First().name into g
                                                            select g.Count();

                            if (subsubquery.Contains(2) || subsubquery.Contains(3))
                            {
                                yakus.Add(LoveLive_MahjongClass.YakuInfo[(int)MahjongYakuType.Ipeko]);
                            }
                        }
                    }
                }
                else
                {
                    // 有役满以上,检查并删除七对子
                    if (isChitoi)
                    {
                        for (int i = 0; i < yakus.Count; i++)
                        {
                            if (yakus[i].type == MahjongYakuType.Chitoi)
                            {
                                yakus.RemoveAt(i);
                                break;
                            }
                        }
                        isChitoi = false;
                    }
                }
            }

            // 检查状态役
            if (Status)
            {
                yakus.AddRange(calcStatusYaku(isYakuman));
            }

            return(yakus);
        }
Beispiel #2
0
        /// <summary>
        /// 能够鸣牌计算
        /// </summary>
        private List <FuruAble> isCanFuru()
        {
            // 获得刚刚打牌的玩家的牌河和打出的牌
            List <MahjongCard> played_cards = GetPlayerCardPlayed(Playing);
            MahjongCard        last_played  = played_cards.Last(); // 最后一张

            // 比对其他三家的手牌
            List <FuruAble> furuAbles = new List <FuruAble>();

            // 记录是否有玩家可以碰或者杠以减少不必要的计算
            bool hasPongKong = false;

            // 遍历所有其它玩家
            for (int player = 0; player < 4; player++)
            {
                if (player == Playing)
                {
                    continue; // 跳过自己
                }

                // 获得手牌
                List <MahjongCard> player_hand = GetPlayerCardOnHand(player);

                // 记录可副露牌组
                FuruAble furuAble = new FuruAble(player);

                // 如果已经有别的玩家可以碰杠,则不可能再有玩家可以碰杠
                if (hasPongKong == false)
                {
                    // 优先找出杠子和刻子
                    IEnumerable <MahjongCard> PongKong = from card in player_hand where card == last_played select card;
                    if (PongKong.Count() >= 2)
                    {
                        hasPongKong = true;

                        // 可以碰
                        furuAble.FuruableList.Add(new MahjongCardFuru()
                        {
                            cards  = Enumerable.Repeat(last_played, 2).ToList(),
                            target = Playing,
                            type   = FuruType.Pong,
                        });

                        if (PongKong.Count() == 3)
                        {
                            // 可以杠
                            furuAble.FuruableList.Add(new MahjongCardFuru()
                            {
                                cards  = Enumerable.Repeat(last_played, 3).ToList(),
                                target = Playing,
                                type   = FuruType.Kong,
                            });
                            hasPongKong = true;
                        }
                    }
                }


                if (last_played.type == MahjongCardType.Char)
                {
                    // 年级和小组顺子(吃)
                    // 年级顺子
                    MahjongCardName      name  = last_played.name;
                    MahjongCardGradeType grade = last_played.grade;
                    MahjongCardGroupType group = last_played.group;
                    IEnumerable <IGrouping <MahjongCardName, MahjongCard> > grade_chi = from card in player_hand
                                                                                        where (card.grade == grade) && (card.name != name) &&
                                                                                        (card.type == MahjongCardType.Char) && (card.@group == @group)
                                                                                        group card by card.name into g
                                                                                        select g;
                    if (grade_chi.Count() == 2)
                    {
                        // 至少要有两种同年级的牌才可以吃
                        // 获得要吃的牌
                        List <MahjongCard> chi = new List <MahjongCard>();
                        foreach (IGrouping <MahjongCardName, MahjongCard> cards in grade_chi)
                        {
                            chi.Add(cards.First());
                        }

                        // 加入可副露列表
                        furuAble.FuruableList.Add(new MahjongCardFuru()
                        {
                            cards  = chi,
                            target = Playing,
                            type   = FuruType.ChiGrade,
                        });
                    }

                    // 小组顺子
                    MahjongCardSquadType squad = last_played.squad;
                    IEnumerable <IGrouping <MahjongCardName, MahjongCard> > squad_chi = from card in player_hand
                                                                                        where (card.squad == squad) && (card.name != name) && (card.type == MahjongCardType.Char)
                                                                                        group card by card.name into g
                                                                                        select g;
                    if (squad_chi.Count() == 2)
                    {
                        // 至少要有两种同小组的牌才可以吃
                        // 获得要吃的牌
                        List <MahjongCard> chi = new List <MahjongCard>();
                        foreach (IGrouping <MahjongCardName, MahjongCard> cards in squad_chi)
                        {
                            chi.Add(cards.First());
                        }

                        // 加入可副露列表
                        furuAble.FuruableList.Add(new MahjongCardFuru()
                        {
                            cards  = chi,
                            target = Playing,
                            type   = FuruType.ChiSquad,
                        });
                    }
                }
                furuAbles.Add(furuAble);
            }

            return(furuAbles);
        }
Beispiel #3
0
        /// <summary>
        ///  和牌判定(除去雀头和副露)
        /// </summary>
        /// <param name="cards">手牌</param>
        /// <param name="start">从第几张手牌开始找刻子</param>
        /// <returns>是否和牌</returns>
        private bool isHu(List <MahjongCard> cards, int start, ref List <HuCard> huCard)
        {
            if (cards.Count == 0)
            {
                return(true); // 空牌和
            }

            if (cards.Count < 3)
            {
                return(false); // 剩牌不和
            }

            // 针对第一张牌开始寻找刻子和顺子
            IEnumerable <MahjongCard> u = from card in cards where card.name == cards[start].name select card;
            int count = u.Count();

            if (count >= 3)
            {
                // 将刻子加入牌组
                HuCard hucard = new HuCard()
                {
                    type  = HuCardType.PongKong,
                    furu  = false,
                    cards = new List <MahjongCard>()
                    {
                        cards[start], cards[start + 1], cards[start + 2]
                    },
                };
                huCard.Add(hucard);

                // 删除这个刻子
                for (int m = 0; m < 3; m++)
                {
                    cards.RemoveAt(start);
                }

                // 递归判和
                return(isHu(cards, ref huCard));
            }
            else
            {
                if (start + 1 < cards.Count)
                {
                    return(isHu(cards, start + 1, ref huCard));
                }
                else
                {
                    // 寻找顺子(年级和小组顺子)
                    MahjongCard cur_card = u.First();

                    // 获得牌种
                    MahjongCardType type = cur_card.type;

                    // 只有角色牌才可以凑成年级或小组顺子
                    if (type == MahjongCardType.Char)
                    {
                        // 获得团体、年级和小组信息
                        MahjongCardGroupType group = cur_card.group;
                        MahjongCardGradeType grade = cur_card.grade;
                        MahjongCardSquadType squad = cur_card.squad;

                        // 确认同团体的牌有至少三张
                        IEnumerable <MahjongCard> same_group = from card in cards where (card.name != cur_card.name) && (card.@group == @group) && (card.type == MahjongCardType.Char) select card;
                        if (same_group.Count() >= 2)
                        {
                            // 判断同年级/同小组
                            IEnumerable <MahjongCard> same_grade = from card in same_group where card.grade == grade select card;
                            IEnumerable <MahjongCard> same_squad = from card in same_group where card.squad == squad select card;
                            IEnumerable <MahjongCard> determine;

                            bool GradeOrSquad = false;
                            if (same_grade.Count() >= 2)
                            {
                                GradeOrSquad = false;
                                determine    = same_grade;         // 判断同年级
                            }
                            else if (same_squad.Count() >= 2)
                            {
                                GradeOrSquad = true;
                                determine    = same_squad; // 判断同小队
                            }
                            else
                            {
                                return(false);
                            }

                            // 每种牌只找出一张
                            IEnumerable <MahjongCard> not_same = from card in determine group card by card.name into g select g.First();

                            if (not_same.Count() >= 2)
                            {
                                MahjongCard[] not_same_cards = not_same.ToArray();

                                // 将顺子加入牌组
                                HuCard hucard = new HuCard()
                                {
                                    type  = (GradeOrSquad) ? HuCardType.SquadChi : HuCardType.GradeChi,
                                    furu  = false,
                                    cards = new List <MahjongCard>()
                                    {
                                        cur_card, not_same_cards[0], not_same_cards[1]
                                    },
                                };
                                huCard.Add(hucard);

                                // 从手牌中删除
                                bool p = true, q = true, r = true; // 防止重复删除
                                for (int i = 0; i < cards.Count; i++)
                                {
                                    if ((cards[i].name == cur_card.name) && p)
                                    {
                                        p = false; cards.RemoveAt(i); i--; continue;
                                    }
                                    if ((cards[i].name == not_same_cards[0].name) && q)
                                    {
                                        q = false; cards.RemoveAt(i); i--; continue;
                                    }
                                    if ((cards[i].name == not_same_cards[1].name) && r)
                                    {
                                        r = false; cards.RemoveAt(i); i--; continue;
                                    }
                                    if (!(p || q || r))
                                    {
                                        break;
                                    }
                                }

                                // 递归判和
                                return(isHu(cards, ref huCard));
                            }
                        }
                    }
                }

                return(false);
            }
        }