2012-02-04 2 views
4

여기서해야 할 일이별로 없습니다. 특정 동작을 수행하는 키 입력의 특정 시퀀스를 갖고 싶습니다.마지막 N 개의 키 스트로크 저장

기본적으로 마지막 N 키 스트로크를 저장해야하며 키를 누르면 가장 최근의 키 입력과 일치하는 시퀀스를 찾습니다. 이 같은

yes 
no 

및 입력 할 때, 내 키 입력 기록이 보인다 :

a 
ab 
abc 
abcn 
abcno 

는 순서 no를 인식하고 적절한을 수행해야하는 시점에서

그래서 내가 두 시퀀스가 ​​있다고 동작. 그래서 오래된 키가 폐기 될 수있다, 유한 길이 있습니다 사용

yeayell 

키 시퀀스 :

year 
yell 

및 입력 등 :

또한 다음과 같은 순서로 작업해야합니다 이 경우 최적의 크기 인 3의 원형 버퍼와 같은 것입니다.

내 키 입력은 Keys 열거 형으로 표시됩니다.

마지막 N 키 스트로크를 저장하고 끝에 시퀀스를 찾을 수있는 데이터 구조 또는 알고리즘을 사용해야합니까?

+2

목록 또는 대기열 kenny

+0

내 목표를 달성하는 데 이러한 데이터 구조를 사용하는 방법을 설명 할 수 있습니까? 나는 그저 내 머리를 감쌀 수 없다. 여기에 코노미 코드의 추적 항목의 –

+0

예 : http://stackoverflow.com/questions/469798/konami-code-in-c-sharp 내가 적절한 답을 쓸 시간이 없어 – roken

답변

1

Rolling hash을 사용하고있어 개념 증명이 어떤 작업을 할 수 있습니다 문자 시퀀스의 모음. 나는 당신이 오직 문자들 (그리고 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

어떻게하면 키 모음에 적용 할 수 있습니까? 그것 뒤에 올바른 생각을 가지고있어. 그리고 나는 당신이'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"를 입력 "nananaba"로 사용합니다. –

+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

빠르고 간단한 방법은 여기

0
반드시

하지 최적의, 그러나 아마 가장 쉽고 재사용 :

CircularBuffer<T> 일반적인 컨테이너를 만듭니다.

이것은 버퍼의 최대 요소 수인 N을 생성자에서 사용합니다.

클래스 마지막 부가가치의 인덱스를 들고 N 요소 인덱스 변수 iT의 배열을 가지고, -1로 초기화한다.

CircularBuffer은 두 가지 방법, 즉 Add(TToString(을 갖는다).

Add있어서 단위 i는, 배열의 적절한 위치에 저장 0N = i IF 및 값 주위를 감싼다. 이것은 단지 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 메서드를 호출하여 찾은 시퀀스가 ​​들어 있는지 확인하십시오.

관련 문제