2012-02-04 7 views
4

私はここで何をするのかと少し迷っています。私はキーストロークの特定のシーケンスを特定のアクションを実行したいです。最後のNキーストロークの保存

私は基本的に最後のNキーストロークを保存する必要があり、キーが押されたら、直近のキーストロークに一致するシーケンスを探します。

だから私は2つの配列を有すると言う:

yes 
no 

を、私はタイプとして、私のキーストロークの歴史は次のようになります。それはシーケンスnoを認識し、適切に実行しなければならないポイント

a 
ab 
abc 
abcn 
abcno 

れますアクション。ので、古いキーストロークを破棄することができ、有限の長さで使用して

yeayell 

キーシーケンス:

year 
yell 

や入力など:

それはまたのような順序で作業する必要があります。この場合最適なサイズ3の循環バッファのようなものです。

私のキーストロークはKeys列挙体で表されます。

最終的なN個のキーストロークを保存し、最後にシーケンスを見つけるために使用するデータ構造またはアルゴリズムを教えてください。

+2

リストまたはキュー kenny

+0

目的を達成するためにこれらのデータ構造を使用する方法を説明できますか?私はちょうどそれの周りに私の頭を包むことはできません。ここでこのみコードの追跡エントリの –

+0

例: http://stackoverflow.com/questions/469798/konami-code-in-c-sharp – roken

答えて

1

を使用しているここでの概念実証あなたがどんなで動作することができますです文字シーケンスのコレクション。私はあなたが文字と一致するだけであると仮定しています(Keys.Leftなどの他のキーではありません)。

// Initialize the collection of strings to be matched against here. 
string[] stringSequences = new string[] { "yes", "no", "hello" }; 
int maxLength = stringSequences.Max(s => s.Length); 

// The buffer to hold the sequence of the last N characters. 
string buffer = ""; 

while (true) 
{ 
    // Read the next character, and append it to the end of the buffer. 
    ConsoleKeyInfo next = Console.ReadKey(); 
    buffer += next.KeyChar; 

    // If the buffer has exceeded our maximum length, 
    // trim characters from its start. 
    if (buffer.Length > maxLength) 
     buffer = buffer.Substring(1); 

    // Check whether the last n characters of the buffer 
    // correspond to any of the sequences. 
    string match = stringSequences.FirstOrDefault(s => buffer.EndsWith(s)); 
    if (match != null) 
    { 
     // Match! Perform any custom processing here. 
     Console.WriteLine(Environment.NewLine + "Match: " + match); 
    } 
} 

編集:キーで動作するようになって。

私はKeysに対して簡単にテストすることができないので、代わりにConsoleKeyを使用しました。ただし、コードを翻訳するのは難しいことではありません。

// Initialize the collection of key sequences to be matched against here. 
ConsoleKey[][] keysSequences = new ConsoleKey[][] 
{ 
    new ConsoleKey[] { ConsoleKey.Y, ConsoleKey.E, ConsoleKey.S }, 
    new ConsoleKey[] { ConsoleKey.N, ConsoleKey.O }, 
    new ConsoleKey[] { ConsoleKey.H, ConsoleKey.E, ConsoleKey.L, ConsoleKey.L, ConsoleKey.O }, 
}; 
int maxLength = keysSequences.Max(ks => ks.Length); 

// The buffer to hold the sequence of the last N keys. 
List<ConsoleKey> buffer = new List<ConsoleKey>(); 

while (true) 
{ 
    // Read the next key, and append it to the end of the buffer. 
    ConsoleKeyInfo next = Console.ReadKey(); 
    buffer.Add(next.Key); 

    // If the buffer has exceeded our maximum length, 
    // trim keys from its start. 
    if (buffer.Count > maxLength) 
     buffer.RemoveAt(0); 

    // Check whether the last n keys of the buffer 
    // correspond to any of the sequences. 
    ConsoleKey[] match = keysSequences.FirstOrDefault(ks => 
     buffer.Skip(buffer.Count - ks.Length).SequenceEqual(ks)); 
    if (match != null) 
    { 
     // Match! Perform any custom processing here. 
     Console.WriteLine(Environment.NewLine + "Match: " + 
      string.Concat(match.Select(k => k.ToString()).ToArray())); 
    } 
} 
+0

これは何とか 'Keys'のコレクションに適合させることができますか?それはその背後に正しいアイデアを持っています。そして私はあなたが 'buffer = buffer.Substring(1)'を意味したと思います。 –

+0

'System.Windows.Forms.Keys'または' System.ConsoleKey'ですか? (はい、あなたはバッファについて正しいです;固定されています) – Douglas

+0

'Microsoft.Xna.Framework.Input.Keys'は' System.Windows.Forms.Keys'とほとんど同じです。 –

0

単純なstate machineはうまくいくはずです。

ルールに従わない入力をリセットすることができます。

enum States 
{ 
initial, 
y, 
e, 
s, 
n, 
o 
} 

if(char == 'n' && state == states.Initial) 
{ 
    state = States.n; 
} 

if(char == 'o' && state == states.n) 
{ 
    state = States.o; 
} 

... // etc for y, e, s - resetting to `Initial` where needed 

... // Check for states o or s 
+2

一般的な方法でこの種の状態マシンを作成することはそれほど簡単ではありません。入力 "ナノナバ"のための "nanaba"を取る –

+0

私は10以上のシーケンスを持ち、それらは多くの共通鍵を持っています。この状況では、これは正しく機能しません。 –

+0

@kendfrey - これは質問に基づく単純な例です。状態は、「ye」、「eye」、「odgye」であってもよい。状態図の作成方法によって異なります。 – Oded

0

あなたは循環バッファを使用することができます。

char[] buf = new char[3]; 
int pos = 0; 

// on key press 
buf[pos] = key; 

if (buf[pos] == 'o' && buf[(pos + 2) % 3] == 'n') 
    No(); 

if (buf[pos] == 's' && buf[(pos + 2) % 3] == 'e' && buf[(pos + 1) % 3] == 'y') 
    Yes(); 

pos = (pos + 1) % 3; 
+1

ハードコードされたシーケンスを使わずにその使い方を説明できますか? 'List 'として各シーケンスを保存するようなもの。 –

0

必ずしも最適ではないが、おそらく最も簡単で、再利用可能:

CircularBuffer<T>汎用コンテナを作成します。

これは、バッファ内の要素の最大数であるNをコンストラクタで1つとります。

クラスは、Nの要素を持つTの配列と、最後に追加された値のインデックスを保持するインデックス変数iを持ち、-1に初期化します。

CircularBufferは、2つの方法、Add(TおよびToString(を有する)。

Add方法増分ii = N場合0程度をラップし、アレイ内の適切な位置に値を格納します。これは、バッファに値を追加して、その中にNしか残さないようにする必要があります。

ToStringは、バッファに格納されているものと同等の文字列を出力します。

      a b c d 

the indices are   0 1 2 3 

the last added value is ^

`ToString` should return 'dabc' 

ここラッピングロジックは、ユーザーのための運動です:N = 4の場合

は、あなたがこの配列を持っていると言います。

キーを押すたびに循環バッファに追加し、そのToStringメソッドを呼び出して、検索するシーケンスが含まれているかどうかを確認します。

関連する問題