Sprawdzenie, czy określona konfiguracja siatki pasuje do określonej receptury, jest proste, jeśli zakodujesz siatkę 3x3 jako ciąg znaków i użyjesz dopasowania wyrażenia regularnego . Przyspieszenie wyszukiwania to inna sprawa, o której w końcu porozmawiam. Czytaj dalej, aby dowiedzieć się więcej.
Krok 1) Zakoduj siatkę jako Ciąg
Wystarczy podać identyfikator każdego typu komórki i połączyć wszystko obok siebie w tej kolejności:
123
456 => 123456789
789
I bardziej konkretny przykład, rozważ przepis na kij, w którym W oznacza drewno, a E jest pustą komórką (możesz po prostu użyć pustego znaku ''):
EEE
WEE => EEEWEEWEE
WEE
Krok 2) Dopasuj przepis przy użyciu wyrażenia regularnego (lub String.Contains z odrobiną przetwarzania danych)
Kontynuując powyższy przykład, nawet jeśli przesuniemy formację, nadal istnieje wzór w sznurku (WEEW wyściełany przez E po obu stronach):
EEW
EEW => EEWEEWEEE
EEE
Niezależnie od tego, gdzie przesuniesz drążek, nadal będzie pasował do następującego wyrażenia regularnego: /^E*WEEWE*$/
Wyrażenia regularne pozwalają również wykonać wspomniane zachowanie warunkowe. Na przykład (wymyślony przepis), jeśli chcesz, aby kilof wykonany z żelaza lub kamienia dawał taki sam efekt, tj .:
III SSS
EWE or EWE
EWE EWE
Możesz połączyć oba w wyrażenie regularne: /^(III)|(SSS)EWEEWE$/
Równie łatwo można dodawać przerzucenia w poziomie (również za pomocą operatora |).
Edycja: W każdym razie część wyrażenia regularnego nie jest absolutnie konieczna. Jest to tylko jeden sposób na zawarcie problemu w jednym wyrażeniu. Jednak w przypadku problemu ze zmienną lokalizacją równie dobrze możesz przyciąć ciąg siatki dowolnych spacji (lub liter E w tym przykładzie) i wykonać String.Contains (). W przypadku problemu z wieloma składnikami lub dublowanych przepisów możesz po prostu obsłużyć je wszystkie jako wiele (tj. Osobne) przepisy o tej samej wydajności.
Krok 3) Przyspieszenie wyszukiwania
Jeśli chodzi o ograniczenie wyszukiwania, musisz utworzyć strukturę danych, aby pogrupować przepisy i pomóc w wyszukiwaniu. Traktowanie siatki jako łańcucha również ma tutaj pewne zalety :
Można zdefiniować „długość” przepisu jako odległość między pierwszym niepustym znakiem a ostatnim niepustym znakiem. Prosty Trim().Length()
podałby ci te informacje. Przepisy można pogrupować według długości i przechowywać w słowniku.
lub
Alternatywną definicją „długości” może być liczba niepustych znaków. Nic innego się nie zmienia. Możesz pogrupować przepisy według tych kryteriów.
Jeśli punkt 1 nie wystarczy, przepisy można również pogrupować według rodzaju pierwszego składnika, który pojawia się w przepisie. Byłoby to tak proste, jak robienie Trim().CharAt(0)
(i ochrona przed przycinaniem skutkującym pustym ciągiem).
Na przykład przechowujesz przepisy w:
Dictionary<int, Dictionary<char, List<string>>> _recipes;
I wykonaj wyszukiwanie jako coś takiego:
// 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
}
}