3x3グリッドを文字列としてエンコードし、正規表現一致を使用する場合、特定のグリッド構成が特定のレシピに一致するかどうかを確認するのは簡単です。ルックアップの高速化は別の問題です。これについては最後に説明します。詳細についてはお読みください。
手順1)グリッドを文字列としてエンコードする
各タイプのセルにchar idを指定し、すべてをこの順序で並べて連結します。
123
456 => 123456789
789
さらに具体的な例として、Wが木材を表し、Eが空のセルであるスティックレシピを考えます(空の文字 ''を使用できます)。
EEE
WEE => EEEWEEWEE
WEE
手順2)正規表現を使用したレシピの一致(または文字列。データの処理が少し含まれています)
上記の例を続けると、フォーメーションを移動しても、文字列にはまだパターンがあります(両側にEが埋め込まれたWEEW):
EEW
EEW => EEWEEWEEE
EEE
したがって、スティックをどこに動かしても、次の正規表現と一致します。 /^E*WEEWE*$/
正規表現を使用すると、前述の条件付き動作も実行できます。たとえば、レシピを作成した場合、鉄または石で作られたつるはしに同じ結果が必要な場合、つまり:
III SSS
EWE or EWE
EWE EWE
両方を正規表現に結合できます。 /^(III)|(SSS)EWEEWE$/
水平反転も同様に簡単に追加できます(|演算子も使用)。
編集: とにかく、正規表現の部分は厳密には必要ありません。問題を単一の式にカプセル化する方法の1つにすぎませんが、変数の場所の問題については、任意のパディングスペース(またはこの例では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
}
}