Перевірити, чи певна конфігурація сітки відповідає певній рецептурі, просто, якщо ви кодуєте сітку 3x3 як рядок і використовуєте відповідність регулярного вираження . Прискорення погляду - це інша справа, про яку я поговорю наприкінці. Читайте далі для отримання додаткової інформації.
Крок 1) Кодування сітки як рядка
Просто введіть знак ідентифікатора для кожного типу комірок і об'єднайте все поряд з цим порядком:
123
456 => 123456789
789
І як конкретніший приклад, розглянемо рецепт палички, де W означає деревину, а E - порожню клітинку (ви можете просто використовувати порожній знак ''):
EEE
WEE => EEEWEEWEE
WEE
Крок 2) Зіставте рецепт за допомогою регулярного вираження (або String.Contes with a bit of obdelava the data)
Продовжуючи з наведеного вище прикладу, навіть якщо ми переміщуємо формацію навколо, у рядку все ще є візерунок (WEEW з E з обох сторін):
EEW
EEW => EEWEEWEEE
EEE
Тож де б ви не пересували палицю, вона все одно буде відповідати наступному регулярному виразу: /^E*WEEWE*$/
Регулярні вирази також дозволяють виконувати згадану вами умовну поведінку. Наприклад (складений рецепт), якщо ви хочете, щоб кирка з заліза або каменю дала такий же результат, тобто:
III SSS
EWE or EWE
EWE EWE
Ви можете поєднати обидва в регулярний вираз: /^(III)|(SSS)EWEEWE$/
Горизонтальні гортання також можна легко додати (використовуючи також оператор |).
Редагувати: У будь-якому разі, частина регулярних виразів не є суворо необхідною. Це лише один спосіб інкапсулювати проблему в один вираз, але для проблеми зі змінним розташуванням ви можете так само добре обрізати сітку рядка будь-яких пробілів (або Е в цьому прикладі) і зробити String.Contains (). А для проблеми з кількома інгредієнтами або дзеркальних рецептів ви можете просто обробити їх усіма кількома (тобто окремими) рецептами з однаковим результатом.
Крок 3) Швидкість пошуку
Що стосується зменшення пошуку, вам потрібно створити структуру даних, щоб групувати рецепти разом і допомагати в пошуку. Трактування сітки як рядка має і деякі переваги тут :
Ви можете визначити "довжину" рецепта як відстань між першим не порожнім символом і останнім не порожнім символом. Простий Trim().Length()
дав би вам цю інформацію. Рецепти можна групувати за довжиною і зберігати у словнику.
або
Альтернативним визначенням "довжина" може бути кількість не порожніх символів. Нічого іншого не змінюється. Ви також могли групувати рецепти за цими критеріями.
Якщо точки № 1 недостатньо, рецепти також можуть бути додатково згруповані за типом першого інгредієнта, який відображається в рецепті. Це було б так само просто, як робити Trim().CharAt(0)
(і захист від обрізання в результаті порожнього рядка).
Так, наприклад, ви зберігаєте рецепти у:
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
}
}