Ver se uma determinada configuração da grade corresponde a uma determinada receita é simples se você codificar a grade 3x3 como uma sequência e usar uma correspondência de expressão regular . Acelerar a pesquisa é um assunto diferente, sobre o qual falarei no final. Continue lendo para obter mais informações.
Etapa 1) Codificar grade como String
Simplesmente forneça um ID de caractere para cada tipo de célula e concatene tudo lado a lado nesta ordem:
123
456 => 123456789
789
E, como exemplo mais concreto, considere a receita do palito, em que W significa madeira e E é uma célula vazia (você pode simplesmente usar um caractere vazio ''):
EEE
WEE => EEEWEEWEE
WEE
Etapa 2) Corresponder Receita usando Expressão Regular (ou String. Contém um pouco de processamento nos dados)
Continuando no exemplo acima, mesmo se movermos a formação, ainda há um padrão na string (WEEW preenchido por E nos dois lados):
EEW
EEW => EEWEEWEEE
EEE
Portanto, não importa para onde você mova o manche, ele ainda corresponderá à seguinte expressão regular: /^E*WEEWE*$/
Expressões regulares também permitem executar o comportamento condicional que você mencionou. Por exemplo (receita confeccionada), se você quiser uma picareta de ferro ou pedra para obter o mesmo resultado, ou seja:
III SSS
EWE or EWE
EWE EWE
Você pode combinar os dois na expressão regular: /^(III)|(SSS)EWEEWE$/
Os movimentos horizontais também podem ser adicionados com a mesma facilidade (usando também o operador |).
Edit: Enfim, a parte regex não é estritamente necessária. É apenas uma maneira de encapsular o problema em uma única expressão. Mas, para o problema de localização variável, você também pode aparar a cadeia de grade de qualquer espaço de preenchimento (ou E neste exemplo) e executar um String.Contains (). E para o problema de vários ingredientes ou as receitas espelhadas, você pode lidar com todos eles como várias receitas (separadas) com a mesma saída.
Etapa 3) Acelerando a pesquisa
Quanto à redução da pesquisa, você precisará criar alguma estrutura de dados para agrupar as receitas e ajudar na pesquisa. Tratar a grade como string também tem algumas vantagens aqui :
Você pode definir o "comprimento" de uma receita como sendo a distância entre o primeiro caractere não vazio e o último caractere não vazio. Um simples Trim().Length()
lhe daria essa informação. As receitas podem ser agrupadas por tamanho e armazenadas em um dicionário.
ou
Uma definição alternativa de "comprimento" pode ser o número de caracteres não vazios. Nada mais muda. Você também pode agrupar receitas por esse critério.
Se o ponto número 1 não for suficiente, as receitas também poderão ser agrupadas de acordo com o tipo do primeiro ingrediente que aparece na receita. Isso seria tão simples quanto fazer Trim().CharAt(0)
(e proteger contra Trim resultando em uma sequência vazia).
Por exemplo, você armazenaria receitas em:
Dictionary<int, Dictionary<char, List<string>>> _recipes;
E execute a pesquisa como algo como:
// 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
}
}