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()); }
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 }); }
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()); }
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()); }
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()); }
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()); }
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 }); }
/// <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)); }
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 }); }
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)); }
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()); }
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 }); }
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 }); }
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 }); }
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)); }