Узнать, соответствует ли определенная конфигурация сетки определенному рецепту, просто, если вы кодируете сетку 3x3 как строку и используете совпадение регулярного выражения . Ускорение поиска - это другой вопрос, о котором я расскажу в конце. Читайте дальше для получения дополнительной информации.
Шаг 1) Кодировать сетку как строку
Просто укажите идентификатор каждого типа ячейки и объедините все рядом в следующем порядке:
123
456 => 123456789
789
И в качестве более конкретного примера рассмотрим рецепт палки, где W обозначает древесину, а E - пустую ячейку (вы можете просто использовать пустой символ ''):
EEE
WEE => EEEWEEWEE
WEE
Шаг 2) Сопоставьте рецепт с помощью регулярного выражения (или String.Contains с небольшим количеством обработки данных)
Продолжая приведенный выше пример, даже если мы переместим формацию вокруг, в строке все равно будет шаблон (WEEW, дополненный E с обеих сторон):
EEW
EEW => EEWEEWEEE
EEE
Поэтому независимо от того, куда вы перемещаете флешку, она все равно будет соответствовать следующему регулярному выражению: /^E*WEEWE*$/
Регулярные выражения также позволяют вам выполнять условное поведение, которое вы упомянули. Например (составленный рецепт), если вы хотели, чтобы кирка из железа или камня дала такой же результат, то есть:
III SSS
EWE or EWE
EWE EWE
Вы можете объединить оба в регулярное выражение: /^(III)|(SSS)EWEEWE$/
Горизонтальные смещения также могут быть добавлены так же легко (с помощью оператора | тоже).
Изменить: Во всяком случае, часть регулярных выражений не является строго необходимым. Это всего лишь один способ инкапсулировать проблему в одном выражении. Но для проблемы с переменным местоположением вы также можете обрезать строку сетки любых пробельных полей (или E в этом примере) и выполнить String.Contains (). А для задачи с несколькими ингредиентами или зеркальных рецептов вы можете просто обрабатывать их как несколько (то есть отдельных) рецептов с одинаковым выходом.
Шаг 3) Ускорение поиска
Что касается сокращения поиска, вам нужно создать некоторую структуру данных, чтобы сгруппировать рецепты и помочь с поиском. Обработка сетки как строки также имеет некоторые преимущества :
Вы можете определить «длину» рецепта как расстояние между первым непустым символом и последним непустым символом. Простое Trim().Length()
дало бы вам эту информацию. Рецепты могут быть сгруппированы по длине и сохранены в словаре.
или же
Альтернативным определением «длины» может быть количество непустых символов. Больше ничего не меняется. Вы также можете сгруппировать рецепты по этим критериям.
Если точки номер 1 недостаточно, рецепты также могут быть сгруппированы по типу первого ингредиента, который появляется в рецепте. Это было бы так же просто, как делать Trim().CharAt(0)
(и защищать от Trim, получая пустую строку).
Так, например, вы должны хранить рецепты в:
Dictionary<int, Dictionary<char, List<string>>> _recipes;
И выполнить поиск как что-то вроде:
// A string encode of your current grid configuration
string grid;
// Get length and first char in our grid
string trim = grid.Trim();
int length = trim.Length();
char firstChar = length==0 ? ' ' : trim[0];
foreach(string recipe in _recipes[length][firstChar])
{
// Check for a match with the recipe
if(Regex.Match(grid, recipe))
{
// We found a matching recipe, do something with it
}
}