Код Konami в C#

22
задан MikeTheLiar 12 June 2015 в 12:42
поделиться

7 ответов

В формах окон у меня был бы класс, который знает то, что последовательность является и содержит состояние того, где Вы находитесь в последовательности. Что-то вроде этого должно сделать это.

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace WindowsFormsApplication3 {
    public class KonamiSequence {

        List<Keys> Keys = new List<Keys>{System.Windows.Forms.Keys.Up, System.Windows.Forms.Keys.Up, 
                                       System.Windows.Forms.Keys.Down, System.Windows.Forms.Keys.Down, 
                                       System.Windows.Forms.Keys.Left, System.Windows.Forms.Keys.Right, 
                                       System.Windows.Forms.Keys.Left, System.Windows.Forms.Keys.Right, 
                                       System.Windows.Forms.Keys.B, System.Windows.Forms.Keys.A};
        private int mPosition = -1;

        public int Position {
            get { return mPosition; }
            private set { mPosition = value; }
        }

        public bool IsCompletedBy(Keys key) {

            if (Keys[Position + 1] == key) {
                // move to next
                Position++;
            }
            else if (Position == 1 && key == System.Windows.Forms.Keys.Up) {
                // stay where we are
            }
            else if (Keys[0] == key) {
                // restart at 1st
                Position = 0;
            }
            else {
                // no match in sequence
                Position = -1;
            }

            if (Position == Keys.Count - 1) {
                Position = -1;
                return true;
            }

            return false;
        }
    }
}

Для использования его Вам было бы нужно что-то в ответе кода Вашей Формы, настраивают события. Что-то вроде этого должно сделать это:

    private KonamiSequence sequence = new KonamiSequence();

    private void Form1_KeyUp(object sender, KeyEventArgs e) {
        if (sequence.IsCompletedBy(e.KeyCode)) {
            MessageBox.Show("KONAMI!!!");
        }
    }

, Надо надеяться, этого достаточно, чтобы дать Вам, в чем Вы нуждаетесь. Для WPF Вам будут нужны незначительные различия, очень похоже (см. историю редактирования № 1).

РЕДАКТИРОВАНИЕ: обновленный для winforms вместо wpf.

24
ответ дан Sam Meldrum 29 November 2019 в 04:33
поделиться

Поймайте нажатия клавиш в 13 (или безотносительно подмножества кода, так как Вы, вероятно, не хотите включать ключ ЗАПУСКА) - символ list/array/string/whatever прежде, чем обычно обрабатывать их. Каждый раз ключ добавляется, если (и только если) это - последний ключ в ряду, соответствуйте буферу против корректного кода konami.

Мое предложение, если они поражают клавишу со стрелкой, отображают ее на разумную букву... тогда карта B и также, просто очищая буфер для какого-либо другого нажатия клавиши.

Затем делая буфер строкой, сравните его с: "UUDDLRLRBABA"

5
ответ дан user54650 29 November 2019 в 04:33
поделиться

должно быть расписание для выполнения? можно поразить последовательность "UUDDLRLRBABA", но при нажатии клавиши 1 в минуту

0
ответ дан 29 November 2019 в 04:33
поделиться

Я рекомендую реализовать как список поисковых событий и ссылочного указателя "получения" на элементы того списка.

Концептуально, Вы запускаете указатель получения на первый элемент поискового списка. Если очень следующее событие соответствует поисковому элементу, указатель получения увеличен к следующему элементу. Иначе это сбрасывается к началу.

, Если указатель увеличен мимо последнего элемента, у Вас есть полное соответствие.

2
ответ дан spoulson 29 November 2019 в 04:33
поделиться

Ответ можно найти в Реактивные расширения . Вам нужен скользящий буфер для этого, чтобы работать. Это означает, что вы должны сравнить последние десять нажатий клавиш с кодом Konami. Это работает с использованием двух разных операторов

  • Окно для получения потока потоков (в конечном итоге приводит к 10 одновременным потокам)
  • Буфер для суммирования каждого потока в IList

Буфер в RX выполняет обе эти задачи за нас. Буферизует последние 10 элементов и пропускает 1 (поэтому эффективно создает 10 буферов).

        var keysIO = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown")
                                    .Select(arg => arg.EventArgs.Key)
                                    .Buffer(10, 1)
                                    .Select(keys => Enumerable.SequenceEqual(keys, _konamiArray))
                                    .Where(result => result)
                                    .Subscribe(i =>
                                                    {
                                                        Debug.WriteLine("Found Konami");
                                                    });

РЕДАКТИРОВАТЬ: Удалено решение по времени., Слишком сложный

РЕДАКТИРОВАТЬ II: Я также взломал решение по тайм-ауту. Прелесть SelectMany: -)

        var keysIO = Observable.FromEventPattern<KeyEventArgs>(this, "KeyDown")
                            .Select(e => e.EventArgs.Key)
                            .Window(10, 1)
                            .SelectMany(obs => obs.Buffer(TimeSpan.FromSeconds(10), 10))
                            .Where(keys => Enumerable.SequenceEqual(_konamiArray, keys))
                            .Subscribe(keys => Debug.Write("Found Konami"));
0
ответ дан markwilde 29 November 2019 в 04:33
поделиться

Правильная последовательность, точно так же, как сама 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;
8
ответ дан 29 November 2019 в 04:33
поделиться

As requested, here's an class that resolves the "issue" of being able to enter the sequence too slowly to be "secret code like." ;)

The original code in the NES cartridge would have been called within a frame routine and thus would have tracked time by counting execution passes.

Since we're relegated to event-driven, object oriented programming, we're going to have to involve events. Since these events will need to enforce an "expiration," we're going to have to involve a Timer object.

using System;
using System.Windows.Forms;
using Timer=System.Timers.Timer;

namespace WindowsApplication1
{
    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 _sequenceIndex;

        private readonly int _codeLength;
        private readonly int _sequenceMax;

        private readonly Timer _quantum = new Timer();

        public KonamiSequence()
        {
            _codeLength = _code.Length - 1;
            _sequenceMax = _code.Length;

            _quantum.Interval = 3000; //ms before reset
            _quantum.Elapsed += timeout;
        }

        public bool IsCompletedBy(Keys key)
        {   
            _quantum.Start();      

            _sequenceIndex %= _sequenceMax;
            _sequenceIndex = (_code[_sequenceIndex] == key) ? ++_sequenceIndex : 0;

            return _sequenceIndex > _codeLength;
        }

        private void timeout(object o, EventArgs e)
        {
            _quantum.Stop();
            _sequenceIndex = 0;

        }
    }
}
4
ответ дан 29 November 2019 в 04:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: