예제 #1
0
        /// <summary>
        /// Checks if the hand has finished on a closed wait.
        /// </summary>
        /// <returns><c>True</c> if contains a closed wait; <c>False</c> otherwise.</returns>
        public bool HandWithClosedWait()
        {
            if (YakusCombinations == null)
            {
                return(false);
            }

            // The combination with the last pick.
            TileComboPivot combo = YakusCombinations.FirstOrDefault(c => c.Tiles.Any(t => ReferenceEquals(t, LatestPick)));

            if (combo == null || combo.IsBrelanOrSquare)
            {
                return(false);
            }

            // Other concealed (and not declared) combinations with the same tile.
            List <TileComboPivot> otherCombos =
                YakusCombinations
                .Where(c => c != combo && !DeclaredCombinations.Contains(c) && c.Tiles.Contains(LatestPick))
                .ToList();

            // The real "LatestPick" is closed...
            bool isClosed = combo.IsPair || LatestPick.TileIsMiddleWait(combo) || LatestPick.TileIsEdgeWait(combo);

            // .. but there might be not-closed alternatives with the same tile as "LatestPick" in other combination.
            bool alternative1 = otherCombos.Any(c => c.IsBrelanOrSquare);
            bool alternative2 = otherCombos.Any(c => c.IsSequence && !LatestPick.TileIsMiddleWait(c) && !LatestPick.TileIsEdgeWait(c));

            return(isClosed && !(alternative1 || alternative2));
        }
예제 #2
0
        /// <summary>
        /// Declares a kan (opened). Does not discard a tile. Does not draw substitution tile.
        /// </summary>
        /// <param name="tile">The stolen tile.</param>
        /// <param name="stolenFrom">The wind which the tile has been stolen from.</param>
        /// <param name="fromOpenPon">The <see cref="TileComboPivot"/>, if the kan is called as an override of a previous pon call; <c>Null</c> otherwise.</param>
        /// <exception cref="ArgumentNullException"><paramref name="tile"/> is <c>Null</c>.</exception>
        /// <exception cref="InvalidOperationException"><see cref="Messages.InvalidCall"/></exception>
        internal void DeclareKan(TilePivot tile, WindPivot?stolenFrom, TileComboPivot fromOpenPon)
        {
            if (tile == null)
            {
                throw new ArgumentNullException(nameof(tile));
            }

            if (fromOpenPon == null)
            {
                CheckTilesForCallAndExtractCombo(_concealedTiles.Where(t => t == tile),
                                                 stolenFrom.HasValue ? 3 : 4,
                                                 stolenFrom.HasValue ? tile : null,
                                                 stolenFrom
                                                 );
            }
            else
            {
                int indexOfPon = _declaredCombinations.IndexOf(fromOpenPon);
                if (indexOfPon < 0 || stolenFrom.HasValue)
                {
                    throw new InvalidOperationException(Messages.InvalidCall);
                }

                var concealedTiles = new List <TilePivot>
                {
                    tile
                };
                concealedTiles.AddRange(fromOpenPon.Tiles.Where(t => !ReferenceEquals(t, fromOpenPon.OpenTile)));

                _declaredCombinations[indexOfPon] = new TileComboPivot(concealedTiles, fromOpenPon.OpenTile, fromOpenPon.StolenFrom);
                _concealedTiles.Remove(tile);
            }
        }
예제 #3
0
 /// <summary>
 /// Checks if the tile is on the closed edge of a sequence combination.
 /// </summary>
 /// <param name="combo">The combination.</param>
 /// <returns><c>True</c> if on the closed edge; <c>False</c> otherwise.</returns>
 public bool TileIsEdgeWait(TileComboPivot combo)
 {
     return(combo != null && combo.IsSequence && combo.Tiles.Contains(this) &&
            (
                (combo.SequenceFirstNumber == 1 && combo.SequenceLastNumber == Number) ||
                (combo.SequenceLastNumber == 9 && combo.SequenceFirstNumber == Number)
            ));
 }
예제 #4
0
        /// <summary>
        /// Checks if a tile can be discarded, but does not discard it.
        /// </summary>
        /// <param name="tile">The tile to discard; should obviously be contained in <see cref="_concealedTiles"/>.</param>
        /// <param name="afterStealing">Optionnal; indicates if the discard is made after stealing a tile; the default value is <c>False</c>.</param>
        /// <returns><c>False</c> if the discard is forbidden by the tile stolen; <c>True</c> otherwise.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="tile"/> is <c>Null</c>.</exception>
        /// <exception cref="InvalidOperationException"><see cref="Messages.ImpossibleDiscard"/></exception>
        /// <exception cref="ArgumentException"><see cref="Messages.ImpossibleStealingArgument"/></exception>
        internal bool CanDiscardTile(TilePivot tile, bool afterStealing = false)
        {
            if (tile == null)
            {
                throw new ArgumentNullException(nameof(tile));
            }

            if (!_concealedTiles.Contains(tile))
            {
                throw new InvalidOperationException(Messages.ImpossibleDiscard);
            }

            if (afterStealing)
            {
                TileComboPivot lastCombination = _declaredCombinations.LastOrDefault();
                if (lastCombination == null || lastCombination.IsConcealed)
                {
                    throw new ArgumentException(Messages.ImpossibleStealingArgument, nameof(afterStealing));
                }
                TilePivot stolenTile = lastCombination.OpenTile;
                if (stolenTile == tile)
                {
                    return(false);
                }
                else if (lastCombination.IsSequence &&
                         tile.Family == lastCombination.Family &&
                         lastCombination.OpenTile.Number == lastCombination.SequenceFirstNumber &&
                         tile.Number == lastCombination.SequenceFirstNumber + 3)
                {
                    return(false);
                }
                else if (lastCombination.IsSequence &&
                         tile.Family == lastCombination.Family &&
                         lastCombination.OpenTile.Number == lastCombination.SequenceLastNumber &&
                         tile.Number == lastCombination.SequenceLastNumber - 3)
                {
                    return(false);
                }
            }

            return(true);
        }
예제 #5
0
 /// <summary>
 /// Checks if the tile is in the middle of a sequence combination.
 /// </summary>
 /// <param name="combo">The combination.</param>
 /// <returns><c>True</c> if in the middle; <c>False</c> otherwise.</returns>
 public bool TileIsMiddleWait(TileComboPivot combo)
 {
     return(combo != null && combo.IsSequence && combo.Tiles.Contains(this) &&
            combo.SequenceFirstNumber != Number &&
            combo.SequenceLastNumber != Number);
 }