Я веду занятия по программированию для школьников. И наблюдаю проблему, в общем-то, очевидно, стандартную для всех школьников, особенно средних классов — у многих очень низкая скорость набора программного текста на клавиатуре.
Естественно, надо предложить детям работать на клавиатурном тренажере. Но, во-первых, я не хочу заставлять детей учить метод слепой (десятипальцевой) печати (это потребует от детей достаточно много времени, и не имеет много смысла на начальном этапе; потом кто захочет — сам выучит). Во-вторых, для программирования, конечно, нужна английская раскладка клавиатуры, но предлагать детям, которые еще не очень-то хорошо знают английский язык, писать сложные английские литературные тексты, как это обычно бывает в клавиатурных тренажерах, — тоже странно.
Когда я сам был школьником, у нас на занятиях по программированию была специальная (самописная) программа-тренажер, которая в качестве словаря использовала реальный словарь языка программирования (выдернутый из справки, насколько я помню). Я решил, что нынешним школьникам надо тоже сделать что-то подобное — чтобы они тренировались на фрагментах, которые реально будут встречаться в программах. При этом они не только будут увеличивать свою скорость набора, но еще и учить собственно программные конструкции.
Таких стандартных тренажеров я не нашел (потом уже мне рассказали, что в Клавогонках есть возможность создания пользовательских словарей, но там все равно функционал явно недостаточен и очень неудобен), поэтому пришлось писать свой.
При этом хотелось, чтобы школьник мог бы получить доступ к тренажеру откуда угодно: с компа в школе, с компа или компов дома с минимальной установкой. Поэтому вариант «расписывать какое-либо ПО на все компы» не очень подходил. В результате я решил сделать тренажер в виде простенького веб-приложения. Точнее даже просто JS-приложения, т.к. все взаимодействие с сетью, естественно, должно происходить только на начальном этапе, чтобы во время собственно набора текста задержки сети не влияли бы на результаты.
Школьникам предлагается одна за другой несколько строк, которые могли бы быть в реальной программе, они набирают их, тренажер подсчитывает скорость набора каждой строки и среднюю скорость набора всех предложенных строк. Время набора строки считается как время, прошедшее с первого нажатия клавиши в строке до финишного нажатия enter; время до первого нажатия клавиши (обычно уходящее на то, чтобы прочитать строку) не учитывается.
Во время пробных запусков обнаружил две проблемы.
Во-первых, надо, конечно, что-то делать, если пользователь набирает текст с опечаткой. Во многих тренажерах при этом так или иначе блокируется возможность дальнейшего набора текста, я реализовал несколько более простой подход (как оно и было в тренажере моих школьных времен) — если строка набрана с опечаткой, которая не была вовремя (до нажатия enter) исправлена, то она помечается как ошибочная и не учитывается при вычислении общей средней скорости набора.
(Конечно, это позволяет читерить — если произошла какая-то задержка набора, то можно просто ввести ерудну и нажать enter — но система и не задумывалась как соревновательная, к тому же, если пытаться устраивать соревнования, то можно учитывать только подходы, в которых все данные строки были набраны верно.)
При этом хочется все-таки как-то указывать пользователю, где он ошибся. Пришлось реализовать стандартный квадратичный алгоритм вычисления расстояния Левенштейна, плюс дополнить его кодом для подсветки ошибок в строке — что оказалось технически не столь тривиально, как я изначально ожидал. (Проблема в том, что надо хранить информацию, находимся мы уже внутри ошибки в каждой строке или нет.)
Во-вторых, захотелось быть не очень жестким в отношении пробелов. Принципы расстановки пробелов в коде у многих программистов различаются, я не хочу заставлять своих школьников с самого начала ставить пробелы строго по какому-нибудь стандарту — поэтому хочется, чтобы тренажер допускал определенную вольность в отношении их наличия или отсутствия. Для этого надо уметь отличать значащие пробелы от незначащих, но, если хочется сделать тренажер универсальным для разных языков программирования (а это, безусловно, надо), то сложно реализовать универсальный корректный подход.
Я решил пожертвовать абсолютной корректностью и стал считать пробел значащим если и слева и справа от него стоят буквенные символы (буквы, цифры или знак подчеркивания). Более строго — берется группа подряд идущих пробелов и, если и слева и справа от нее стоят буквенные символы, то первый пробел из этой группы считается значащим. Конечно, это далеко не всегда корректно (элементарный контрпример — пробелы внутри строковых констант), но это разумный компромисс между простотой, универсальностью и корректностью. Пришлось немного подкрутить код для расстояния Левенштейна и добавить переключатель для любителей строгости.
Итог получился вполне рабочий, дети используют. Особые мастера научились получать заоблачные скорости путем копирования заданной строки в буфер обмена и вставки ее в поле ввода — я решил, что смысла закрывать эту проблему нет, шутники и так всегда найдутся, а нормальным школьникам эта проблема не мешает.
Код на github: github.com/petr-kalinin/keyb
Live на github.io: petr-kalinin.github.io/keyb/
(Словари там, конечно, довольно простые — для совсем-совсем начинающих школьников.)
Автор: pkalinin