Всем привет.
В школьном и более продвинутом курсе информатики есть учебный язык - Кукарача. Довольно удачный, для обучения детей программированию. Простой, понятный, визуальные результаты с первой строчки.
Авторы курса сделали только exe-шник под Windows. Когда младший сын начал требовать "Папа научи программировать" принял волевое решение - сделаю свою имплементацию. И сделал.
Че это вообще?
Есть прямоугольное поле. Жучок и буквочки. Нужно писать программы, что бы жучок правильным образом подвигал буковки.
Поддерживаются простые команды - ВВЕРХ
, ВНИЗ
, ВПРАВО
, ВЛЕВО
и их группировка с помощью {}
.
После каждого действия известен результат - какую букву толкнул жучок.
Есть циклы - ПОВТОРИ x
, ПОКА y
и условие ЕСЛИ z ТО ... ИНАЧЕ ...
И даже процедуры - ЭТО proc_name ... КОНЕЦ
Поэтому, в процессе обучения ребенок учится довольно сложных концепциям включая рекурсию и процедурное программирование.
Поле
Поле работает совсем очевидно - массивчик char'ов и специальный символ для жучка. Процедуры, которые передвигают жучка изменяя состояние. Запоминаем последнюю букву, которую толкнули. Осталось добавить загрузку/выгрузку в строку примерно такого вида:
А_А__
_1_1_
_____
____~
а также колбек на изменение, что бы отрисовывать и симпатичный компонент готов.
Как сделать интерпретатор?
Оказалось, что сделать интерпретатор не так уж и сложно. Надо понимать что такое синтаксис и грамматика, почитать немного примеров и воспользоваться готовыми либами.
Я взял antlr - т.к мой основной язык java и там этот генератор парсеров на слуху. В итоге получилась такая грамматика
грамматика
grammar Cockroach;
@header {
package ru.nizhikov.cockroach.antlr;
}
prog
: exprs EOF
;
exprs
: expr+
;
expr
: statement
| repeat
| while
| if
| proc
| id
| LINE_COMMENT
;
statement
: UP
| DOWN
| LEFT
| RIGHT
| STAY
| group
;
repeat
: REPEAT NUM expr
;
while
: WHILE condition expr
;
group
: OPEN_BRACKET exprs CLOSE_BRACKET
;
if
: IF condition THEN statement (ELSE statement)?
;
proc
: THIS id exprs END
;
condition
: NOT? id
| NOT? EMPTY
| NOT? NUMBER
;
id
: ID
;
LINE_COMMENT : '//' ~[\n\r]* -> skip;
UP: 'ВВЕРХ';
DOWN: 'ВНИЗ';
LEFT: 'ВЛЕВО';
RIGHT: 'ВПРАВО';
STAY: 'СТОЯТЬ';
NOT: 'НЕ';
EMPTY: 'ПУСТО';
NUMBER: 'ЦИФРА';
REPEAT: 'ПОВТОРИ';
WHILE: 'ПОКА';
CHAR: 'БУКВА';
OPEN_BRACKET: '{';
CLOSE_BRACKET: '}';
IF: 'ЕСЛИ';
THEN: 'ТО';
ELSE: 'ИНАЧЕ';
THIS: 'ЭТО';
END: 'КОНЕЦ';
ID: LETTER (LETTER | DIGIT)*;
LETTER: [a-zA-Zа-яА-Я];
NUM: DIGIT+;
DIGIT: [0-9];
SPACE: [ \r\n\t]+ -> skip;
Грамматика задает правила для парсера что бы из текста сформировать синтаксическое дерево. Пример на картинке.
Интерпретатору всего-лишь надо обойти это дерево верным образом и выполнить необходимые действия. Действия следуют из их смысла:
Определение процедуры - запоминаем имя процедуры в специальной мапке. Ключ - название, значение - поддерево команд.
Вызов процедуры (токен ID) - ищем определение процедуры и вызываем соответствующее поддерево команд.
Цикл
ПОВТОРИ x
- выполняем поддеревоx
раз.Цикл
ПОКА у
- проверяем условиеy
и выполняем поддерево пока оно выполняется.ЕСЛИ z ТО ... ИНАЧЕ ...
- проверяем условиеz
и выполняем то или иное поддерево.Обычные команды - изменяем состояние поля.
Интерфейс
Последний раз я делал UI еще во времена когда jquery и extjs были модными :), поэтому погуглив как сейчас делается интерфейс слегка ох^Wудивился обилию возможностей. В итоге собрал из туториала который первым заработал рабочее one page application и запилил с помощью того что знаю - bootstrap и jquery.
Очень хотелось сделать подсветку синтаксиса, а нагугленный компонент поддерживал другой генератор парсеров. Нет проблем - записать грамматику немного другим синтаксисом проще простого.
Несмотря на то, что в CodeMirror довольно подробная документация разобраться в API оказалось не так просто. Возможно, я отвык от уровня документирования js компонент. Но, в итоге, подсветка синтаксиса и текущей команды во время дебага и запуска работает.
Сохранение файликов сделал через localStorage - удобненько.
Сложности
Первая реализация интерпретатора написана на java и работает через консоль. Пошаговое выполнение (отладку) легко сделать через ожидание ввода с консоли.
А вот в javascript простой возможности останавить выполнение в рандомном месте нет. Поэтому, пришлось заморочиться и сделать, что бы интерпретация приложения работала на promise'ах. Команда кукарачи выполняется при выполнении Promise.resolve
.
Публикация
Вкратце - github прекрасен)
Оказалось, что в github есть бесплатный, автоматизированный, удобный функционал, что бы опубликовать one page application. Называется github pages. Обалденно удобно. Собираешь свое приложение, указываешь папочку, жмешь кнопку и вуаля - приложение готово и работает.
Ну вот и все pet project готов и вроде как работает. Ребенок два раза позанимался программированием и получил массу удовольствия. Я тоже доволен и пописал интересный код.
Иходники - https://github.com/nizhikov/cockroach
А еще у меня есть канал с выступлениями и ссылками на интересные пейперы из мира разработки СУБД.
Комментарии (24)
ris58h
19.09.2022 19:10+2У меня в детстве на уроках информатики Исполнитель "Муравей" был. Чем-то похоже.
По интерфейсу: не очень понял зачем столько кнопок, хотя может детям так понятнее. Я бы оставил Сбросить и Выполнять/Остановить (как Play/Stop в проигрывателях). Плюс Следующая, которая не активна, если идёт автоматическое выполнение.
P.S.: создал issue на GitHub по другой проблеме.
Tutanhomon
19.09.2022 19:50+3У нас на "Немигах" стояла "Черепашка". Там похожий синтаксис был - "пока справа стена - вверх"
s_f1
19.09.2022 19:50+1Не понял, чем отличается Таракан от Лого, поэтому ввёл размер поля 999 х 999, и браузеру поплохело.
pavel_raskin
19.09.2022 21:23+3Очень напоминает старый
добрыйКуМир и его прародителя "Школьный алгоритмический язык". Не совсем понятно, зачем авторы "Роботландии" разрабатывали свой вариант учебного языка, повторив ранее реализованную идею почти без изменений.
BMBM
19.09.2022 22:54-7Привет, но мир наших потомков уже не 2д... 0ну0же0о ориентирован е в xmll,,0 0js0on днн0ых0 про это нужн0ы0 ур0оки
siroBS
20.09.2022 10:02+4Мой первый ЯП (не тьюринг-полный):
Кто знает, может именно это послужило "запечатлением" :)))
pilot2k
20.09.2022 10:07Серьезно?
с синтаксисом на русском?)))NorthDragon Автор
20.09.2022 10:07+3Круто же? Особенно для детей :)
pilot2k
20.09.2022 10:10не круто, заодно учили бы английский и в будущем было бы проще
все равно без английского никудаNorthDragon Автор
20.09.2022 10:11+3Детям тяжело внимание удерживать. Поэтому в приоритете не нагружать голову лишним. Английские слова, в данном контексте лишние.
pilot2k
20.09.2022 10:35а о каком возрасте речь?
NorthDragon Автор
20.09.2022 10:367-9 лет
pilot2k
20.09.2022 18:00и еще не учат иностранный язык?
странно, у меня уже был английский в таком возрасте
Iscander_Che
20.09.2022 10:18Как жучок буквы двигает? Как бульдозер?
Я начинал с Бейсика. :)
NorthDragon Автор
20.09.2022 10:19Ну да - при движении в любую сторону все буквочки сдвигаются на клетку.
Их даже можно сбрасывать с поля - детям очень нравится.
Paskin
Советую вам взглянуть на Logo (Lynx) и Scratch.
NorthDragon Автор
Спасибо, конечно я знаю про эти средства.
Scratch, в той школе где мы занимались, изучают во вторую очередь.
Хотя, лично мне это средство не понравилось. Возможно, у меня визуальный способ подачи информации не мое)
alan008
В Python есть логовская черепашка в виде отдельной библиотеки:
вот она
Megadeth77
Вот это открытие! Спасибо! То что надо для детишек, просто для начала, а то ascii графонием в терминале заинтересовать нереально.