Exemple #1
0
        /// <summary>
        /// Checks if <see cref="Yakus"/> and <see cref="YakusCombinations"/> have to be cancelled because of the temporary furiten rule.
        /// </summary>
        /// <param name="currentRound">The current round</param>
        /// <param name="playerIndex">The player index of the hand.</param>
        /// <returns><c>True</c> if temporary furiten; <c>False</c> otherwise.</returns>
        internal bool CancelYakusIfTemporaryFuriten(RoundPivot currentRound, int playerIndex)
        {
            if (currentRound == null)
            {
                return(false);
            }

            int i = 0;

            while (currentRound.PlayerIndexHistory.Count < i &&
                   currentRound.PlayerIndexHistory.ElementAt(i) == playerIndex.RelativePlayerIndex(-(i + 1)) &&
                   playerIndex.RelativePlayerIndex(-(i + 1)) != playerIndex)
            {
                // The tile discarded by the latest player is the tile we ron !
                if (i > 0)
                {
                    TilePivot lastFromDiscard = currentRound.GetDiscard(currentRound.PlayerIndexHistory.ElementAt(i)).LastOrDefault();
                    if (lastFromDiscard != null && IsCompleteFull(new List <TilePivot>(ConcealedTiles)
                    {
                        lastFromDiscard
                    }, DeclaredCombinations.ToList()))
                    {
                        Yakus             = null;
                        YakusCombinations = null;
                        return(true);
                    }
                }
                i++;
            }

            return(false);
        }
Exemple #2
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="humanPlayerName">The name of the human player; other players will be <see cref="PlayerPivot.IsCpu"/>.</param>
        /// <param name="initialPointsRule">The <see cref="InitialPointsRule"/> value.</param>
        /// <param name="endOfGameRule">The <see cref="EndOfGameRule"/> value.</param>
        /// <param name="save">Player save stats.</param>
        /// <param name="withRedDoras">Optionnal; the <see cref="WithRedDoras"/> value; default value is <c>False</c>.</param>
        /// <param name="useNagashiMangan">Optionnal; the <see cref="UseNagashiMangan"/> value; default value is <c>False</c>.</param>
        /// <param name="useRenhou">Optionnal; the <see cref="UseRenhou"/> value; default value is <c>False</c>.</param>
        public GamePivot(string humanPlayerName,
                         InitialPointsRulePivot initialPointsRule,
                         EndOfGameRulePivot endOfGameRule,
                         PlayerSavePivot save,
                         bool withRedDoras     = false,
                         bool useNagashiMangan = false,
                         bool useRenhou        = false)
        {
            _save = save;

            InitialPointsRule  = initialPointsRule;
            EndOfGameRule      = endOfGameRule;
            _players           = PlayerPivot.GetFourPlayers(humanPlayerName, InitialPointsRule);
            DominantWind       = WindPivot.East;
            EastIndexTurnCount = 1;
            EastIndex          = FirstEastIndex;
            EastRank           = 1;
            WithRedDoras       = withRedDoras;
            UseNagashiMangan   = useNagashiMangan;
            UseRenhou          = useRenhou;

            Round = new RoundPivot(this, EastIndex);
        }
Exemple #3
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="round">The <see cref="_round"/> value.</param>
 /// <exception cref="ArgumentNullException"><paramref name="round"/> is <c>Null</c>.</exception>
 internal IaManagerPivot(RoundPivot round)
 {
     _round = round ?? throw new ArgumentNullException(nameof(round));
 }
Exemple #4
0
        /// <summary>
        /// Manages the end of the current round and generates a new one.
        /// <see cref="Round"/> stays <c>Null</c> at the end of the game.
        /// </summary>
        /// <param name="ronPlayerIndex">The player index on who the call has been made; <c>Null</c> if tsumo or ryuukyoku.</param>
        /// <returns>An instance of <see cref="EndOfRoundInformationsPivot"/>.</returns>
        public EndOfRoundInformationsPivot NextRound(int?ronPlayerIndex)
        {
            var endOfRoundInformations = Round.EndOfRound(ronPlayerIndex);

            // used for stats
            var humanIsRiichi    = Round.IsRiichi(HUMAN_INDEX);
            var humanIsConcealed = Round.GetHand(HUMAN_INDEX).IsConcealed;

            if (!endOfRoundInformations.Ryuukyoku)
            {
                PendingRiichiCount = 0;
            }

            if (!endOfRoundInformations.ToNextEast || endOfRoundInformations.Ryuukyoku)
            {
                HonbaCount++;
            }

            if (EndOfGameRule.TobiRuleApply() && _players.Any(p => p.Points < 0))
            {
                endOfRoundInformations.EndOfGame = true;
                ClearPendingRiichi();
                goto Exit;
            }

            if (DominantWind == WindPivot.West || DominantWind == WindPivot.North)
            {
                if (!endOfRoundInformations.Ryuukyoku && _players.Any(p => p.Points >= 30000))
                {
                    endOfRoundInformations.EndOfGame = true;
                    ClearPendingRiichi();
                    goto Exit;
                }
            }

            if (endOfRoundInformations.ToNextEast)
            {
                EastIndex          = EastIndex.RelativePlayerIndex(1);
                EastIndexTurnCount = 1;
                EastRank++;

                if (EastIndex == FirstEastIndex)
                {
                    EastRank = 1;
                    if (DominantWind == WindPivot.South)
                    {
                        if (EndOfGameRule.EnchousenRuleApply() &&
                            InitialPointsRule == InitialPointsRulePivot.K25 &&
                            _players.All(p => p.Points < 30000))
                        {
                            DominantWind = WindPivot.West;
                        }
                        else
                        {
                            endOfRoundInformations.EndOfGame = true;
                            ClearPendingRiichi();
                            goto Exit;
                        }
                    }
                    else if (DominantWind == WindPivot.West)
                    {
                        DominantWind = WindPivot.North;
                    }
                    else if (DominantWind == WindPivot.North)
                    {
                        endOfRoundInformations.EndOfGame = true;
                        ClearPendingRiichi();
                        goto Exit;
                    }
                    else
                    {
                        DominantWind = WindPivot.South;
                    }
                }
            }
            else
            {
                EastIndexTurnCount++;
            }

            Round = new RoundPivot(this, EastIndex);

Exit:
            var me = Players.Single(_ => !_.IsCpu);

            _save.UpdateAndSave(endOfRoundInformations,
                                ronPlayerIndex.HasValue,
                                humanIsRiichi,
                                humanIsConcealed,
                                Players.OrderByDescending(_ => _.Points).ToList().IndexOf(me),
                                me.Points);

            return(endOfRoundInformations);
        }