public string Generate(Board _board, GameUnit _unit, GameUnit _finishUnit)
        {
            var stringBuilder = new StringBuilder();
            var words = MagicWordsStore.Words
                                       .Concat(SpecialWords)
                                       .ToArray();
            var usedUnits = new HashSet<GameUnit>();
            while (!_unit.Equals(_finishUnit))
            {
                if (TimeLimiter.NeedStop())
                    break;

                foreach (var powerWord in words.OrderByDescending(x => x.Length))
                {
                    if (TimeLimiter.NeedStop())
                        break;

                    var newlyUsedUnits = new HashSet<GameUnit>();
                    var currentUnit = _unit;
                    var fail = false;
                    for (var i = 0; i < powerWord.Length; ++i)
                    {
                        var command = powerWord[i];
                        newlyUsedUnits.Add(currentUnit);
                        var nextUnit = currentUnit.MakeStep(CommandConverter.Convert(command));
                        var locked = !_board.IsValid(nextUnit);
                        if (newlyUsedUnits.Contains(nextUnit) ||
                            usedUnits.Contains(nextUnit) ||
                            (locked && i < powerWord.Length - 1) ||
                            (locked && !nextUnit.Equals(_finishUnit)))
                        {
                            fail = true;
                            break;
                        }
                        if (!locked)
                        {
                            currentUnit = nextUnit;
                        }
                    }
                    var allUsedUnits = new HashSet<GameUnit>(usedUnits.Union(newlyUsedUnits));
                    if (!fail && ReachableStatesGetter.CanReach(_board, currentUnit, false, allUsedUnits, _finishUnit))
                    {
                        _unit = currentUnit;
                        usedUnits = allUsedUnits;
                        stringBuilder.Append(powerWord);
                        break;
                    }
                }
            }
            foreach (var command in Enum.GetValues(typeof(Command)).Cast<Command>().Except(new[] { Command.Empty }))
            {
                if (!_board.IsValid(_unit.MakeStep(command)))
                {
                    stringBuilder.Append(CommandConverter.CovertToAnyChar(command));
                    break;
                }
            }
            return stringBuilder.ToString();
        }
        private static void Dfs(Board board, GameUnit unit, HashSet<GameUnit> newlyUsedUnits, HashSet<GameUnit> previouslyUsedUnits, HashSet<GameUnit> lockedUnits)
        {
            newlyUsedUnits.Add(unit);

            foreach (var command in Commands)
            {
                var nextUnit = unit.MakeStep(command);
                if (!previouslyUsedUnits.Contains(nextUnit) && !newlyUsedUnits.Contains(nextUnit))
                {
                    if (board.IsValid(nextUnit))
                    {
                        Dfs(board, nextUnit, newlyUsedUnits, previouslyUsedUnits, lockedUnits);
                    }
                    else if (lockedUnits != null)
                    {
                        lockedUnits.Add(unit);
                    }
                }
            }
        }
        private static bool Dfs2(Board board, GameUnit unit, HashSet<GameUnit> newlyUsedUnits, HashSet<GameUnit> previouslyUsedUnits, HashSet<GameUnit> lockedUnits, GameUnit finishUnit)
        {
            if (unit.Equals(finishUnit))
                return true;
            newlyUsedUnits.Add(unit);

            foreach (var command in Commands)
            {
                var nextUnit = unit.MakeStep(command);
                if (!previouslyUsedUnits.Contains(nextUnit) && !newlyUsedUnits.Contains(nextUnit))
                {
                    if (board.IsValid(nextUnit) && Dfs2(board, nextUnit, newlyUsedUnits, previouslyUsedUnits, lockedUnits, finishUnit))
                    {
                        return true;
                    }
                    else if (lockedUnits != null)
                    {
                        lockedUnits.Add(unit);
                    }
                }
            }
            return false;
        }
        private bool CanMove(GameUnit unit, string word, out GameUnit nextUnit)
        {
            var tuple = new Tuple<GameUnit, string>(unit, word);
            if (moves.TryGetValue(tuple, out nextUnit))
            {
                return nextUnit != null;
            }

            var gameUnits = new HashSet<GameUnit>();
            gameUnits.Add(unit);
            nextUnit = unit;
            foreach (var command in word)
            {
                nextUnit = nextUnit.MakeStep(CommandConverter.Convert(command));
                if (gameUnits.Contains(nextUnit) || !board.IsValid(nextUnit))
                {
                    moves[tuple] = null;
                    return false;
                }
                gameUnits.Add(nextUnit);
            }

            moves[tuple] = nextUnit;
            return true;
        }