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