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