Esempio n. 1
0
 public static YakuValue 抢杠(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                            RoundStatus roundStatus, GameSetting settings)
 {
     return(handStatus.HasFlag(HandStatus.RobKong) ? new YakuValue {
         Name = "抢杠", Value = 1
     } : new YakuValue());
 }
Esempio n. 2
0
 public static YakuValue 天地和(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                             RoundStatus roundStatus, GameSetting settings)
 {
     if (!handStatus.HasFlag(HandStatus.Tsumo) || !handStatus.HasFlag(HandStatus.Menqing) ||
         !handStatus.HasFlag(HandStatus.FirstTurn))
     {
         return(new YakuValue());
     }
     return(roundStatus.IsDealer
         ? new YakuValue {
         Name = "天和", Value = 1, Type = YakuType.Yakuman
     }
         : new YakuValue {
         Name = "地和", Value = 1, Type = YakuType.Yakuman
     });
 }
Esempio n. 3
0
        public static YakuValue 平和(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                   RoundStatus roundStatus, GameSetting settings)
        {
            if (!handStatus.HasFlag(HandStatus.Menqing))
            {
                return(new YakuValue());
            }
            int  countOfSequence = 0;
            bool twoSide         = false;

            foreach (var meld in decompose)
            {
                if (meld.Type != MeldType.Pair && meld.Type != MeldType.Sequence)
                {
                    return(new YakuValue());
                }
                if (meld.Type == MeldType.Sequence)
                {
                    countOfSequence++;
                    twoSide = twoSide || meld.IsTwoSideIgnoreColor(winningTile);
                }
            }

            if (countOfSequence == 4 && twoSide)
            {
                return new YakuValue {
                           Name = "平和", Value = 1
                }
            }
            ;
            return(new YakuValue());
        }
Esempio n. 4
0
        public static YakuValue  色同顺(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                     RoundStatus roundStatus, GameSetting settings)
        {
            const int flag     = 1 + (1 << 9) + (1 << 18); // binary : 1000000001000000001
            int       handFlag = 0;

            foreach (var meld in decompose)
            {
                if (meld.Type != MeldType.Sequence || meld.Suit == Suit.Z)
                {
                    continue;
                }
                handFlag |= 1 << Tile.GetIndex(meld.First);
            }

            Assert.IsTrue(handFlag >= 0, "Only 27 flag bits, this number should not be less than 0");
            for (int i = 0; i < 9; i++)
            {
                if ((handFlag & flag) == flag)
                {
                    return new YakuValue {
                               Name = "三色同顺", Value = handStatus.HasFlag(HandStatus.Menqing) ? 2 : 1
                    }
                }
                ;
                handFlag >>= 1;
            }

            return(new YakuValue());
        }
Esempio n. 5
0
        public static YakuValue 一气(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                   RoundStatus roundStatus, GameSetting settings)
        {
            const int flag     = 73; // binary : 1001001
            int       handFlag = 0;

            foreach (var meld in decompose)
            {
                if (meld.Type != MeldType.Sequence)
                {
                    continue;
                }
                handFlag |= 1 << Tile.GetIndex(meld.First);
            }

            Assert.IsTrue(handFlag >= 0, "Only 27 flag bits, this number should not be less than 0");

            while (handFlag > 0)
            {
                if ((handFlag & flag) == flag)
                {
                    return new YakuValue {
                               Name = "一气通贯", Value = handStatus.HasFlag(HandStatus.Menqing) ? 2 : 1
                    }
                }
                ;
                handFlag >>= 9;
            }

            return(new YakuValue());
        }
Esempio n. 6
0
 public static YakuValue 立直(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                            RoundStatus roundStatus, GameSetting settings)
 {
     if (handStatus.HasFlag(HandStatus.Menqing) && handStatus.HasFlag(HandStatus.Richi))
     {
         return new YakuValue {
                    Name = "立直", Value = 1
         }
     }
     ;
     if (handStatus.HasFlag(HandStatus.Menqing) && handStatus.HasFlag(HandStatus.WRichi))
     {
         return new YakuValue {
                    Name = "双立直", Value = 2
         }
     }
     ;
     return(new YakuValue());
 }
Esempio n. 7
0
        public static YakuValue 暗刻系(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                    RoundStatus roundStatus, GameSetting settings)
        {
            var count = decompose.Count(meld => meld.Type == MeldType.Triplet && !meld.Revealed);

            if (count < 3)
            {
                return(new YakuValue());
            }
            Assert.IsTrue(count >= 3 && count <= 4, "There could not be more than 4 triplets in a complete hand");
            var winningTileInOther = decompose.Any(meld => !meld.Revealed &&
                                                   (meld.Type == MeldType.Pair ||
                                                    meld.Type == MeldType.Sequence) &&
                                                   meld.ContainsIgnoreColor(winningTile));

            if (handStatus.HasFlag(HandStatus.Tsumo))
            {
                if (count == 3)
                {
                    return new YakuValue {
                               Name = "三暗刻", Value = 2
                    }
                }
                ;
                // count == 4
                return(winningTileInOther
                                        ? new YakuValue {
                    Name = "四暗刻·单骑听", Value = settings.四暗刻单骑, Type = YakuType.Yakuman
                }
                                        : new YakuValue {
                    Name = "四暗刻", Value = 1, Type = YakuType.Yakuman
                });
            }

            if (count == 3 && !winningTileInOther)
            {
                return(new YakuValue());
            }
            if (count == 3 && winningTileInOther)
            {
                return new YakuValue {
                           Name = "三暗刻", Value = 2
                }
            }
            ;
            // count == 4
            return(winningTileInOther
                                ? new YakuValue {
                Name = "四暗刻·单骑听", Value = settings.四暗刻单骑, Type = YakuType.Yakuman
            }
                                : new YakuValue {
                Name = "三暗刻", Value = 2
            });
        }
Esempio n. 8
0
        /// <summary>
        /// Note: lingshang and haidi should be obtained in baseHandStatus
        /// </summary>
        /// <param name="playerIndex"></param>
        /// <param name="CurrentRoundStatus"></param>
        /// <param name="winningTile"></param>
        /// <param name="baseHandStatus"></param>
        /// <returns></returns>
        public static PointInfo GetPointInfo(int playerIndex, ServerRoundStatus CurrentRoundStatus, Tile winningTile,
                                             HandStatus baseHandStatus, Tile[] doraTiles, Tile[] uraDoraTiles, int beiDora, GameSetting yakuSettings)
        {
            var zhenting = CurrentRoundStatus.IsZhenting(playerIndex);

            if (zhenting && !baseHandStatus.HasFlag(HandStatus.Tsumo))
            {
                return(new PointInfo());
            }
            var handData   = CurrentRoundStatus.HandData(playerIndex);
            var handStatus = baseHandStatus;

            if (MahjongLogic.TestMenqing(handData.Melds))
            {
                handStatus |= HandStatus.Menqing;
            }
            // test richi
            if (CurrentRoundStatus.RichiStatus(playerIndex))
            {
                handStatus |= HandStatus.Richi;
                // test one-shot
                if (yakuSettings.HasOneShot && CurrentRoundStatus.OneShotStatus(playerIndex))
                {
                    handStatus |= HandStatus.OneShot;
                }
                // test WRichi
                if (CurrentRoundStatus.FirstTurn)
                {
                    handStatus |= HandStatus.WRichi;
                }
            }

            // test first turn
            if (CurrentRoundStatus.FirstTurn)
            {
                handStatus |= HandStatus.FirstTurn;
            }
            var roundStatus = new RoundStatus
            {
                PlayerIndex       = playerIndex,
                OyaPlayerIndex    = CurrentRoundStatus.OyaPlayerIndex,
                CurrentExtraRound = CurrentRoundStatus.Extra,
                RichiSticks       = CurrentRoundStatus.RichiSticks,
                FieldCount        = CurrentRoundStatus.Field,
                TotalPlayer       = CurrentRoundStatus.TotalPlayers
            };
            var isQTJ = CurrentRoundStatus.GameSettings.GameMode == GameMode.QTJ;

            return(MahjongLogic.GetPointInfo(handData.HandTiles, handData.Melds, winningTile,
                                             handStatus, roundStatus, yakuSettings, isQTJ, doraTiles, uraDoraTiles, beiDora));
        }
Esempio n. 9
0
        public static YakuValue 一色系(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                    RoundStatus roundStatus, GameSetting settings)
        {
            // 字一色 has already been handled in 全带系
            var allM   = decompose.All(meld => meld.Suit == Suit.M || meld.Suit == Suit.Z);
            var allS   = decompose.All(meld => meld.Suit == Suit.S || meld.Suit == Suit.Z);
            var allP   = decompose.All(meld => meld.Suit == Suit.P || meld.Suit == Suit.Z);
            var single = allM || allS || allP;

            if (!single)
            {
                return(new YakuValue());
            }
            var anyZ = decompose.Any(meld => meld.Suit == Suit.Z);

            return(anyZ
                                ? new YakuValue {
                Name = "混一色", Value = handStatus.HasFlag(HandStatus.Menqing) ? 3 : 2
            }
                                : new YakuValue {
                Name = "清一色", Value = handStatus.HasFlag(HandStatus.Menqing) ? 6 : 5
            });
        }
Esempio n. 10
0
        public static PointInfo GetPointInfo(Tile[] handTiles, Meld[] openMelds, Tile winningTile,
                                             HandStatus handStatus, RoundStatus roundStatus, GameSetting settings, bool isQTJ,
                                             Tile[] doraTiles = null, Tile[] uraDoraTiles = null, int beiDora = 0)
        {
            var decomposes = Decompose(handTiles, openMelds, winningTile);

            if (decomposes.Count == 0)
            {
                return(new PointInfo());
            }
            // count dora
            int dora    = CountDora(handTiles, openMelds, winningTile, doraTiles);
            int uraDora = 0;

            if (handStatus.HasFlag(HandStatus.Richi) || handStatus.HasFlag(HandStatus.WRichi))
            {
                uraDora = CountDora(handTiles, openMelds, winningTile, uraDoraTiles);
            }

            int redDora = CountRed(handTiles, openMelds, winningTile);

            return(GetPointInfo(decomposes, winningTile, handStatus, roundStatus, settings, isQTJ, dora, uraDora, redDora, beiDora));
        }
Esempio n. 11
0
        public static YakuValue 杯口系(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                    RoundStatus roundStatus, GameSetting settings)
        {
            if (!handStatus.HasFlag(HandStatus.Menqing))
            {
                return(new YakuValue());
            }
            int handFlag = 0;
            int count    = 0;

            foreach (var meld in decompose)
            {
                if (meld.Type != MeldType.Sequence)
                {
                    continue;
                }
                int tileFlag = 1 << Tile.GetIndex(meld.First);
                if ((handFlag & tileFlag) != 0)
                {
                    count++;
                    handFlag ^= tileFlag;                     // toggle that bit, aka make it 0 again
                }
                else
                {
                    handFlag |= tileFlag;
                }
            }

            Assert.IsTrue(handFlag >= 0, "Only 27 flag bits, this number should not be less than 0");
            if (count == 2)
            {
                return new YakuValue {
                           Name = "二杯口", Value = 3
                }
            }
            ;
            if (count == 1)
            {
                return new YakuValue {
                           Name = "一杯口", Value = 1
                }
            }
            ;

            return(new YakuValue());
        }
Esempio n. 12
0
        public static YakuValue 九莲(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                   RoundStatus roundStatus, GameSetting settings)
        {
            if (!handStatus.HasFlag(HandStatus.Menqing))
            {
                return(new YakuValue());
            }
            var first = decompose[0];
            var all   = decompose.All(meld => meld.Suit == first.Suit);

            if (!all)
            {
                return(new YakuValue());
            }
            var counts = new int[9];

            foreach (var meld in decompose)
            {
                foreach (var tile in meld.Tiles)
                {
                    counts[tile.Rank - 1]++;
                }
            }

            if (counts[0] < 3 || counts[8] < 3)
            {
                return(new YakuValue());
            }

            for (int i = 1; i < 8; i++)
            {
                if (counts[i] < 1)
                {
                    return(new YakuValue());
                }
            }

            return(counts[winningTile.Rank - 1] == 2 || counts[winningTile.Rank - 1] == 4
                                ? new YakuValue {
                Name = "纯正九连宝灯", Value = settings.纯正九连宝灯, Type = YakuType.Yakuman
            }
                                : new YakuValue {
                Name = "九连宝灯", Value = 1, Type = YakuType.Yakuman
            });
        }
Esempio n. 13
0
        public static YakuValue 断幺九(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                    RoundStatus roundStatus, GameSetting settings)
        {
            if (!settings.OpenDuanYao && !handStatus.HasFlag(HandStatus.Menqing))
            {
                return(new YakuValue());
            }
            foreach (var meld in decompose)
            {
                if (meld.HasYaojiu)
                {
                    return(new YakuValue());
                }
            }

            return(new YakuValue {
                Name = "断幺九", Value = 1
            });
        }
Esempio n. 14
0
        public static YakuValue 七对子(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                    RoundStatus roundStatus, GameSetting settings)
        {
            if (!handStatus.HasFlag(HandStatus.Menqing))
            {
                return(new YakuValue());
            }
            if (decompose.Count != 7)
            {
                return(new YakuValue());
            }
            foreach (var meld in decompose)
            {
                if (meld.Type != MeldType.Pair)
                {
                    return(new YakuValue());
                }
            }

            return(new YakuValue {
                Name = "七对子", Value = 2
            });
        }
Esempio n. 15
0
        public static int CountFu(List <Meld> decompose, Tile winningTile, HandStatus handStatus,
                                  RoundStatus roundStatus, IList <YakuValue> yakus, GameSetting settings)
        {
            if (decompose.Count == 7)
            {
                return(25);                      // 7 pairs
            }
            if (decompose.Count == 13)
            {
                return(30); // 13 orphans
            }
            int fu = 20;    // base fu

            // Menqing and not tsumo
            if (handStatus.HasFlag(HandStatus.Menqing) && !handStatus.HasFlag(HandStatus.Tsumo))
            {
                fu += 10;
            }
            // Tsumo
            if (handStatus.HasFlag(HandStatus.Tsumo) && !yakus.Any(yaku => yaku.Name == "平和" || yaku.Name == "岭上开花"))
            {
                fu += 2;
            }
            // pair
            var pair = decompose.First(meld => meld.Type == MeldType.Pair);

            if (pair.Suit == Suit.Z)
            {
                if (pair.First.Rank >= 5 && pair.First.Rank <= 7)
                {
                    fu += 2;                                               // dragons
                }
                var selfWind       = roundStatus.SelfWind;
                var prevailingWind = roundStatus.PrevailingWind;
                if (pair.First.EqualsIgnoreColor(selfWind))
                {
                    fu += 2;
                }

                if (pair.First.EqualsIgnoreColor(prevailingWind))
                {
                    if (!prevailingWind.EqualsIgnoreColor(selfWind) ||
                        settings.连风对子额外加符)
                    {
                        fu += 2;
                    }
                }
            }

            // sequences
            int flag = 0;

            foreach (var meld in decompose)
            {
                if (!meld.Tiles.Contains(winningTile))
                {
                    continue;
                }
                if (meld.Type == MeldType.Pair)
                {
                    flag++;
                }
                if (meld.Type == MeldType.Sequence && !meld.Revealed && meld.IsTwoSideIgnoreColor(winningTile))
                {
                    flag++;
                }
            }

            if (flag != 0)
            {
                fu += 2;
            }
            // triplets
            var winningTileInOther = decompose.Any(meld => !meld.Revealed &&
                                                   (meld.Type == MeldType.Pair ||
                                                    meld.Type == MeldType.Sequence) &&
                                                   meld.ContainsIgnoreColor(winningTile));

            foreach (var meld in decompose)
            {
                if (meld.Type != MeldType.Triplet)
                {
                    continue;
                }
                if (meld.Revealed)
                {
                    fu += GetTripletFu(meld, true);
                }
                else if (handStatus.HasFlag(HandStatus.Tsumo))
                {
                    fu += GetTripletFu(meld, false);
                }
                else if (winningTileInOther)
                {
                    fu += GetTripletFu(meld, false);
                }
                else if (meld.ContainsIgnoreColor(winningTile))
                {
                    fu += GetTripletFu(meld, true);
                }
                else
                {
                    fu += GetTripletFu(meld, false);
                }
            }

            return(ToNextUnit(fu, 10));
        }