public DpInfo CalcDp(State state)
        {
            if (dp.ContainsKey(state))
            {
                return dp[state];
            }
            if (state.Unit.Equals(target) && state.IsLocked)
            {
                return dp[state] = new DpInfo(0, null, string.Empty, 0);
            }
            if (state.IsLocked)
            {
                return dp[state] = new DpInfo(-1, null, string.Empty, 0);
            }
            if (state.Unit.Equals(target))
            {
                foreach (var command in Enum.GetValues(typeof(Command)).Cast<Command>())
                {
                    GameUnit nextUnit;
                    var word = CommandConverter.CovertToAnyChar(command).ToString();
                    if (!CanMove(state.Unit, word, out nextUnit))
                    {
                        return dp[state] = new DpInfo(0, new State(state.Unit, command, true, true, false), word, 0);
                    }
                }
                return dp[state] = new DpInfo(-1, null, string.Empty, 0);
            }

            if (!state.CanGoHorisontal)
            {
                var best = new DpInfo(-1, null, string.Empty, 0);
                dp[state] = best;

                foreach (var word in words)
                {
                    GameUnit nextUnit;
                    if (AvailablePair(state.LastCommand, state.IsLastCommandWord, CommandConverter.Convert(word.First()), word.Length > 1) && CanMove(state.Unit, word, out nextUnit))
                    {
                        var nextState = new State(nextUnit, CommandConverter.Convert(word.Last()), false, true, word.Length > 1);
                        var dpInfo = CalcDp(nextState);
                        if (dpInfo.Value < 0)
                        {
                            continue;
                        }

                        var newValue = dpInfo.Value + (word.Length == 1 ? 0 : word.Length);
                        if (newValue > best.Value || (newValue == best.Value && dpInfo.ExtraMoves < best.ExtraMoves))
                        {
                            best = new DpInfo(newValue, nextState, word, dpInfo.ExtraMoves);
                        }
                    }
                }

                return dp[state] = best;
            }

            var result = CalcDp(new State(state.Unit, state.LastCommand, state.IsLocked, false, state.IsLastCommandWord));
            dp[state] = result;

            foreach (var horizontalWord in HorizontalWords)
            {
                //ответ для некоторых элементов компоненты сильной связанности может быть меньше, чем надо. Может еще допилю. Вдруг не критично
                GameUnit nextUnit;
                if (AvailablePair(state.LastCommand, state.IsLastCommandWord, CommandConverter.Convert(horizontalWord.First()), false) && CanMove(state.Unit, horizontalWord, out nextUnit))
                {
                    var nextState = new State(nextUnit, CommandConverter.Convert(horizontalWord.Last()), false, true, false);
                    var dpInfo = CalcDp(nextState);
                    if (dpInfo.Value < 0)
                    {
                        continue;
                    }

                    var newValue = dpInfo.Value;
                    if (newValue > result.Value || (newValue == result.Value && dpInfo.ExtraMoves + 1 < result.ExtraMoves))
                    {
                        result = new DpInfo(newValue, nextState, horizontalWord, dpInfo.ExtraMoves + 1);
                    }
                }
            }

            return dp[state] = result;
        }
Пример #2
0
 public bool Equals(State other)
 {
     return Unit.Equals(other.Unit) && LastCommand == other.LastCommand && IsLocked == other.IsLocked && IsLastCommandWord == other.IsLastCommandWord && CanGoHorisontal == other.CanGoHorisontal;
 }
        public string Generate(Board _board, GameUnit _unit, GameUnit _finishUnit)
        {
            board = _board;
            target = _finishUnit;
            moves = new Dictionary<Tuple<GameUnit, string>, GameUnit>();
            words = MagicWordsStore.Words.Concat(SpecialWords).OrderByDescending(x => x.Length).ToArray();
            dp = new Dictionary<State, DpInfo>();

            var state = new State(_unit, Command.Empty, false, true, null);
            CalcDp(state);
            var stringBuilder = new StringBuilder();

            while (!(state.Unit.Equals(target) && state.IsLocked))
            {
                var dpInfo = dp[state];
                stringBuilder.Append(dpInfo.Word);
                state = dpInfo.NextState.Value;
            }

            return stringBuilder.ToString();
        }