public override int ChooseIndexOfTileToDiscard()
        {
            UpdateSeenTiles();
            var indexOfTileToDiscard   = Hand.UncalledTiles.Count - 1;
            var currentWaitingDistance = WaitingDistanceFinder.GetWaitingDistance(Hand.UncalledTiles);
            var bestEfficientDrawCount = 0;

            for (int i = 0; i < Hand.UncalledTiles.Count; i++)
            {
                var remainingTiles = new List <Tile>(Hand.UncalledTiles);
                remainingTiles.RemoveAt(i);
                if (WaitingDistanceFinder.GetWaitingDistance(remainingTiles) > currentWaitingDistance)
                {
                    continue;
                }

                var newEfficientDrawCount = EfficientDrawsFinder.GetEfficientDrawCountWithSeenTiles(remainingTiles,
                                                                                                    SeenTiles);

                if (newEfficientDrawCount > bestEfficientDrawCount)
                {
                    bestEfficientDrawCount = newEfficientDrawCount;
                    indexOfTileToDiscard   = i;
                }
            }
            return(indexOfTileToDiscard);
        }
        public TileGrouping ChooseGroupToMakeWithDiscardedTile(Tile discardedTile, bool canBeSequence)
        {
            UpdateSeenTiles();
            var potentialHandTiles = new List <Tile>(Hand.UncalledTiles)
            {
                discardedTile
            };
            var groupsInvolvingDiscardedTile = GetAllGroupsThatCanBeMadeWithDiscardedTile(discardedTile, canBeSequence);

            var minimumWaitingDistance = WaitingDistanceFinder.GetWaitingDistance(Hand.UncalledTiles);
            var maximumTileEfficiency  = EfficientDrawsFinder.GetEfficientDrawCountWithSeenTiles(Hand.UncalledTiles,
                                                                                                 SeenTiles);
            TileGrouping idealGroup = null;

            foreach (var group in groupsInvolvingDiscardedTile)
            {
                var remainingTiles = new List <Tile>(potentialHandTiles);
                foreach (var tile in group)
                {
                    remainingTiles.Remove(tile);
                }

                var newWaitingDistance = WaitingDistanceFinder.GetWaitingDistance(remainingTiles);
                var newTileEfficiency  = EfficientDrawsFinder.GetEfficientDrawCountWithSeenTiles(remainingTiles,
                                                                                                 SeenTiles);
                if (newWaitingDistance < minimumWaitingDistance ||
                    (newWaitingDistance == minimumWaitingDistance && newTileEfficiency > maximumTileEfficiency))
                {
                    minimumWaitingDistance = newWaitingDistance;
                    maximumTileEfficiency  = newTileEfficiency;
                    idealGroup             = group;
                }
            }
            return(idealGroup);
        }
        public override bool IsClaimingDiscardedTileToCompleteGroup(Tile discardedTile, bool canBeSequence)
        {
            UpdateSeenTiles();
            var potentialHandTiles = new List <Tile>(Hand.UncalledTiles)
            {
                discardedTile
            };
            var groupsInvolvingDiscardedTile = GetAllGroupsThatCanBeMadeWithDiscardedTile(discardedTile, canBeSequence);

            var currentWaitingDistance = WaitingDistanceFinder.GetWaitingDistance(Hand.UncalledTiles);
            var currentTileEfficiency  = EfficientDrawsFinder.GetEfficientDrawCountWithSeenTiles(Hand.UncalledTiles,
                                                                                                 SeenTiles);

            foreach (var group in groupsInvolvingDiscardedTile)
            {
                var remainingTiles = new List <Tile>(potentialHandTiles);
                foreach (var tile in group)
                {
                    remainingTiles.Remove(tile);
                }
                var newWaitingDistance = WaitingDistanceFinder.GetWaitingDistance(remainingTiles);
                if (newWaitingDistance < currentWaitingDistance ||
                    (newWaitingDistance == currentWaitingDistance &&
                     EfficientDrawsFinder.GetEfficientDrawCountWithSeenTiles(remainingTiles, SeenTiles)
                     > currentTileEfficiency))
                {
                    return(true);
                }
            }
            return(false);
        }