Ejemplo n.º 1
0
        /// <summary>
        /// Computes the list of yakus available with this sequence of combinations.
        /// If the list contains one or several yakumans, it can't contain any regular yakus.
        /// Two <see cref="YakuPivot"/> are not computed :
        /// <list type="bullet">
        /// <item><see cref="KokushiMusou"/></item>
        /// <item><see cref="NagashiMangan"/></item>
        /// </list>
        /// </summary>
        /// <param name="combinationsSequence">Sequence of combinations.</param>
        /// <param name="context">Context.</param>
        /// <returns>List of yakus with this sequence of combinations.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="combinationsSequence"/> is <c>Null</c>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="context"/> is <c>Null</c>.</exception>
        /// <exception cref="NotImplementedException">The <see cref="YakuPivot"/> to check is not implemented.</exception>
        public static List <YakuPivot> GetYakus(List <TileComboPivot> combinationsSequence, WinContextPivot context)
        {
            if (combinationsSequence == null)
            {
                throw new ArgumentNullException(nameof(combinationsSequence));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var yakus = new List <YakuPivot>();

            foreach (YakuPivot yaku in Yakus.Where(y => y.IsYakuman))
            {
                bool addYaku = false;
                if (yaku == Daisangen)
                {
                    addYaku = combinationsSequence.Count(c => c.IsBrelanOrSquare && c.Family == FamilyPivot.Dragon) == 3;
                }
                else if (yaku == Suuankou)
                {
                    addYaku = combinationsSequence.Count(c => c.IsBrelanOrSquare && c.IsConcealed && (!c.Tiles.Contains(context.LatestTile) || context.DrawType.IsSelfDraw())) == 4;
                }
                else if (yaku == Shousuushii)
                {
                    addYaku = combinationsSequence.Count(c => c.IsBrelanOrSquare && c.Family == FamilyPivot.Wind) == 3 &&
                              combinationsSequence.Any(c => c.IsPair && c.Family == FamilyPivot.Wind);
                }
                else if (yaku == Daisuushii)
                {
                    addYaku = combinationsSequence.Count(c => c.IsBrelanOrSquare && c.Family == FamilyPivot.Wind) == 4;
                }
                else if (yaku == Tsuuiisou)
                {
                    addYaku = combinationsSequence.All(c => c.IsHonor);
                }
                else if (yaku == Ryuuiisou)
                {
                    addYaku = combinationsSequence.All(c =>
                                                       (c.Family == FamilyPivot.Bamboo && c.Tiles.All(t => new[] { 2, 3, 4, 6, 8 }.Contains(t.Number))) ||
                                                       (c.Family == FamilyPivot.Dragon && c.Tiles.First().Dragon == DragonPivot.Green)
                                                       );
                }
                else if (yaku == Chinroutou)
                {
                    addYaku = combinationsSequence.All(c => c.IsTerminal);
                }
                else if (yaku == ChuurenPoutou)
                {
                    if (combinationsSequence.All(c => c.IsConcealed) &&
                        combinationsSequence.Select(c => c.Family).Distinct().Count() == 1)
                    {
                        string numberPattern = string.Join(string.Empty, combinationsSequence.SelectMany(c => c.Tiles).Select(t => t.Number).OrderBy(i => i));
                        addYaku = new[]
                        {
                            "11112345678999", "11122345678999", "11123345678999",
                            "11123445678999", "11123455678999", "11123456678999",
                            "11123456778999", "11123456788999", "11123456789999"
                        }.Contains(numberPattern);
                    }
                }
                else if (yaku == Suukantsu)
                {
                    addYaku = combinationsSequence.Count(c => c.IsSquare) == 4;
                }
                else if (yaku == Tenhou)
                {
                    addYaku = context.IsTenhou();
                }
                else if (yaku == Chiihou)
                {
                    addYaku = context.IsChiihou();
                }
                else if (yaku == Renhou)
                {
                    addYaku = context.IsRenhou();
                }
                else if (yaku == KokushiMusou)
                {
                    // Do nothing here, but prevents the exception below.
                }
                else
                {
                    throw new NotImplementedException();
                }

                if (addYaku)
                {
                    yakus.Add(yaku);
                }
            }

            // Remove yakumans with existant upgrade (it's an overkill as the only known case is "Shousuushii" vs. "Daisuushii").
            yakus.RemoveAll(y => y.Upgrades.Any(yu => yakus.Contains(yu)));

            // Only return yakumans if any.
            if (yakus.Count >= 1)
            {
                return(yakus);
            }

            foreach (YakuPivot yaku in Yakus.Where(y => !y.IsYakuman))
            {
                bool addYaku    = false;
                int  occurences = 1;
                if (yaku == Chiniisou)
                {
                    addYaku = combinationsSequence.Select(c => c.Family).Distinct().Count() == 1 &&
                              !combinationsSequence.Any(c => c.IsHonor);
                }
                else if (yaku == Haitei)
                {
                    addYaku = context.IsRoundLastTile;
                }
                else if (yaku == RinshanKaihou)
                {
                    addYaku = context.DrawType == DrawTypePivot.Compensation;
                }
                else if (yaku == Chankan)
                {
                    addYaku = context.DrawType == DrawTypePivot.OpponentKanCallOpen;
                }
                else if (yaku == Tanyao)
                {
                    addYaku = combinationsSequence.All(c => !c.HasTerminalOrHonor);
                }
                else if (yaku == Yakuhai)
                {
                    occurences = combinationsSequence.Count(c =>
                                                            c.IsBrelanOrSquare && (
                                                                c.Family == FamilyPivot.Dragon || (
                                                                    c.Family == FamilyPivot.Wind && (
                                                                        c.Tiles.First().Wind == context.DominantWind || c.Tiles.First().Wind == context.PlayerWind
                                                                        )
                                                                    )
                                                                )
                                                            );
                    addYaku = occurences > 0;
                }
                else if (yaku == Riichi)
                {
                    addYaku = context.IsRiichi;
                }
                else if (yaku == Ippatsu)
                {
                    addYaku = context.IsIppatsu;
                }
                else if (yaku == MenzenTsumo)
                {
                    addYaku = context.DrawType.IsSelfDraw() && combinationsSequence.All(c => c.IsConcealed);
                }
                else if (yaku == Honiisou)
                {
                    addYaku = combinationsSequence.Where(c => !c.IsHonor).Select(c => c.Family).Distinct().Count() == 1;
                }
                else if (yaku == Pinfu)
                {
                    addYaku = combinationsSequence.Count(c => c.IsSequence && c.IsConcealed) == 4 &&
                              !HandPivot.HandWithValuablePair(combinationsSequence, context.DominantWind, context.PlayerWind) &&
                              combinationsSequence.Any(c => c.IsSequence && c.Tiles.Contains(context.LatestTile) &&
                                                       !context.LatestTile.TileIsEdgeWait(c) && !context.LatestTile.TileIsMiddleWait(c));
                }
                else if (yaku == Iipeikou)
                {
                    int sequencesCount = combinationsSequence.Count(c => c.IsSequence);
                    addYaku = combinationsSequence.All(c => c.IsConcealed) && sequencesCount >= 2 &&
                              combinationsSequence.Where(c => c.IsSequence).Distinct().Count() < sequencesCount;
                }
                else if (yaku == Shousangen)
                {
                    addYaku = combinationsSequence.Count(c => c.IsBrelanOrSquare && c.Family == FamilyPivot.Dragon) == 2 &&
                              combinationsSequence.Any(c => c.IsPair && c.Family == FamilyPivot.Dragon);
                }
                else if (yaku == Honroutou)
                {
                    addYaku = combinationsSequence.All(c => c.IsTerminal || c.IsHonor);
                }
                else if (yaku == Chiitoitsu)
                {
                    addYaku = combinationsSequence.All(c => c.IsPair);
                }
                else if (yaku == Sankantsu)
                {
                    addYaku = combinationsSequence.Count(c => c.IsSquare) == 3;
                }
                else if (yaku == SanshokuDoukou)
                {
                    addYaku = combinationsSequence
                              .Where(c => c.IsBrelanOrSquare && !c.IsHonor)
                              .GroupBy(c => c.Tiles.First().Number)
                              .FirstOrDefault(b => b.Count() >= 3)?
                              .Select(b => b.Family)?
                              .Distinct()?
                              .Count() == 3;
                }
                else if (yaku == Sanankou)
                {
                    addYaku = combinationsSequence.Count(c => c.IsBrelanOrSquare && c.IsConcealed && (!c.Tiles.Contains(context.LatestTile) || context.DrawType.IsSelfDraw())) == 3;
                }
                else if (yaku == Toitoi)
                {
                    addYaku = combinationsSequence.Count(c => c.IsBrelanOrSquare) == 4;
                }
                else if (yaku == Ittsu)
                {
                    List <TileComboPivot> ittsuFamilyCombos =
                        combinationsSequence
                        .Where(c => c.IsSequence)
                        .GroupBy(c => c.Family)
                        .FirstOrDefault(b => b.Count() >= 3)?
                        .ToList();

                    addYaku = ittsuFamilyCombos != null &&
                              ittsuFamilyCombos.Any(c => c.SequenceFirstNumber == 1) &&
                              ittsuFamilyCombos.Any(c => c.SequenceFirstNumber == 4) &&
                              ittsuFamilyCombos.Any(c => c.SequenceFirstNumber == 7);
                }
                else if (yaku == SanshokuDoujun)
                {
                    addYaku = combinationsSequence
                              .Where(c => c.IsSequence)
                              .GroupBy(c => c.SequenceFirstNumber)
                              .FirstOrDefault(b => b.Count() >= 3)?
                              .Select(b => b.Family)?
                              .Distinct()?
                              .Count() == 3;
                }
                else if (yaku == Chanta)
                {
                    addYaku = combinationsSequence.All(c => c.HasTerminalOrHonor);
                }
                else if (yaku == DaburuRiichi)
                {
                    addYaku = context.IsRiichi && context.IsFirstTurnRiichi;
                }
                else if (yaku == Ryanpeikou)
                {
                    addYaku = combinationsSequence.All(c => c.IsConcealed) &&
                              combinationsSequence.Count(c => c.IsSequence) == 4 &&
                              combinationsSequence.Where(c => c.IsSequence).Distinct().Count() <= 2;
                }
                else if (yaku == Junchan)
                {
                    addYaku = combinationsSequence.All(c => c.HasTerminal);
                }
                else if (yaku == NagashiMangan)
                {
                    // Do nothing here, but prevents the exception below.
                }
                else
                {
                    throw new NotImplementedException();
                }

                if (addYaku)
                {
                    for (int i = 0; i < occurences; i++)
                    {
                        yakus.Add(yaku);
                    }
                }
            }

            // Remove yakus with existant upgrade.
            // It works because Upgrades is not recursive.
            yakus.RemoveAll(y => y.Upgrades.Any(yu => yakus.Contains(yu)));

            // On a concealed chanka, only Kokushi is allowed.
            if (context.DrawType == DrawTypePivot.OpponentKanCallConcealed && !yakus.Contains(KokushiMusou))
            {
                yakus.Clear();
            }

            return(yakus);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Computes and sets properties <see cref="Yakus"/> and <see cref="YakusCombinations"/>.
        /// </summary>
        /// <param name="context">The winning context.</param>
        internal void SetYakus(WinContextPivot context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var concealedTiles = new List <TilePivot>(_concealedTiles);

            if (!context.DrawType.IsSelfDraw())
            {
                concealedTiles.Add(context.LatestTile);
            }

            if (!concealedTiles.Contains(context.LatestTile))
            {
                throw new InvalidOperationException(Messages.InvalidLatestTileContext);
            }

            int tilesCount = concealedTiles.Count + _declaredCombinations.Count * 3;

            if (tilesCount != 14 && !context.IsNagashiMangan)
            {
                throw new InvalidOperationException(Messages.InvalidHandTilesCount);
            }

            Yakus             = null;
            YakusCombinations = null;

            List <List <TileComboPivot> > regularCombinationsSequences = IsCompleteBasic(concealedTiles, new List <TileComboPivot>(_declaredCombinations));

            if (IsSevenPairs(concealedTiles))
            {
                regularCombinationsSequences.Add(new List <TileComboPivot>(concealedTiles.GroupBy(t => t).Select(c => new TileComboPivot(c))));
            }

            var yakusSequences = new Dictionary <List <YakuPivot>, List <TileComboPivot> >();

            if (IsThirteenOrphans(concealedTiles))
            {
                var yakus = new List <YakuPivot>()
                {
                    YakuPivot.KokushiMusou
                };
                if (context.IsTenhou())
                {
                    yakus.Add(YakuPivot.Tenhou);
                }
                else if (context.IsChiihou())
                {
                    yakus.Add(YakuPivot.Chiihou);
                }
                else if (context.IsRenhou())
                {
                    yakus.Add(YakuPivot.Renhou);
                }
                yakusSequences.Add(yakus, null);
            }
            else if (context.IsNagashiMangan)
            {
                yakusSequences.Add(new List <YakuPivot> {
                    YakuPivot.NagashiMangan
                }, null);
            }
            else
            {
                foreach (List <TileComboPivot> combinationsSequence in regularCombinationsSequences)
                {
                    List <YakuPivot> yakus = YakuPivot.GetYakus(combinationsSequence, context);
                    yakusSequences.Add(yakus, combinationsSequence);
                }
            }

            List <YakuPivot> bestYakusSequence = YakuPivot.GetBestYakusFromList(yakusSequences.Keys, IsConcealed);

            if (bestYakusSequence.Count > 0)
            {
                Yakus             = bestYakusSequence;
                YakusCombinations = yakusSequences[bestYakusSequence];
            }
        }