Правильная последовательность, так же, как это реализовала бы сама Konami:
- получить ввод
- если вход равен байту в индексе массива кода, индекс приращения
- если индекс больше длины кода, код правильный
Вот как НЕ сделать этого:
Накапливает буфер нажатий клавиш, а затем выполняет байтовое сравнение строк. Неэффективно, в лучшем случае. Вы выполняете вызовы в подпрограммах разбора строк для каждого нажатия клавиши в форме, и эти процедуры медленны и громоздки по сравнению с некоторыми простыми шагами, которые можно предпринять, чтобы получить тот же точный эффект.
Конечный автомат, который каждый раз ломается, если вы повторяете последовательности в коде.
Конечный автомат, в котором жестко заданы «особые случаи». Теперь вы не можете вносить изменения в одном месте. Вы должны изменить строку кода и добавить новый код, чтобы иметь дело с неверно реализованным конечным автоматом.
Создание объекта List для хранения чего-то простого, например, списка символов.
Задействовать объекты String.
Итак, вот как это сделать:
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class KonamiSequence
{
readonly Keys[] _code = { Keys.Up, Keys.Up, Keys.Down, Keys.Down, Keys.Left, Keys.Right, Keys.Left, Keys.Right, Keys.B, Keys.A };
private int _offset;
private readonly int _length, _target;
public KonamiSequence()
{
_length = _code.Length - 1;
_target = _code.Length;
}
public bool IsCompletedBy(Keys key)
{
_offset %= _target;
if (key == _code[_offset]) _offset++;
else if (key == _code[0]) _offset = 2; // repeat index
return _offset > _length;
}
}
}
Теперь это быстро, не работает со строками и не создает ничего более объемного, чем массив, и изменения в коде так же просты, как и изменение массива.
Инициализация поля в конструкторе заменяет константы жесткого кодирования, эквивалентные необходимым значениям. Если бы мы использовали константы, мы могли бы сократить код примерно на 6 строк. Это немного расточительно, но позволяет максимально легко адаптировать класс к новым кодам - вам просто нужно изменить список массивов. Кроме того, вся «масса» обрабатывается во время создания экземпляра, поэтому это не влияет на эффективность нашего целевого метода.
На второй взгляд этот код можно сделать еще проще. Модуль не требуется, если вы сбрасываете значение при правильном вводе кода.
Логика ядра фактически может быть превращена в одну строку кода:
_sequenceIndex = (_code[_sequenceIndex] == key) ? ++_sequenceIndex : 0;