В теме "Логика верхнего уровня" я уже рассматривал взаимодейтвие программ
написанных на КП и Delphi, но выложенный там пример носил демонстрационный
характер и не был предназначен для практического использования.
Сейчас я предлагаю интерфейс взаимодействия КП и Delphi, вполне пригодный
для практического применения программистами, желающими писать логику
верхнего уровня своих программ по-русски.
Предлагаемый интерфейс взаимодействия КП и Delphi
Программа на Delphi вызывает обработчики событий из DLL на КП, которая,
в свою очередь, вызывает функции нижнего уровня из DLL на Delphi.
Схема интерфейса между КП и Delphi выглядит следующим образом:
Вложение:
kpdelphi.jpg [ 58.17 КБ | Просмотров: 9430 ]
Для реализации приводимого примера я использовал школьную сборку
BlackBox 1.5 (с целью русификации исходного кода на КП) и Delphi 4.
Написанные на Delphi 4 проекты columns и pasdll будут собираться и под
Delphi 2010 и выше, но чтобы предлагаемый интерфейс между КП и Delphi
работал, нужно чтобы columns и pasdll были собраны в одной версии Delphi.
Файл \i21edu\Rsrc\ru.odc мне пришлось редактировать, хотя бы потому, что
там нет русских аналогов для цикла repeat until и для встроенных процедур
inc и dec.
Возможно, что использованные мной определения ЦИКЛ_ДО КОНЕЦ_ЦИКЛА_ДО,
УВЕЛИЧИТЬ, УМЕНЬШИТЬ и не являются идеальными, но лучше что-то, чем вообще
ничего.
Исходя из общего определения ПЕРЕМЕННАЯ:ТИП типы переменных (за исключением
массивов) я решил писать в единственном числе мужского рода.
Привожу фрагмент модуля columnsKpdll (размер columnsKpdll примерно 15 кБ,
593 строки) с основной логикой игры columns, реализацию которой на Delphi
я написал для себя лет 10 тому назад, а сейчас как пример реализации
интерфейса между КП и Delphi решил перетащить ее на КП в слегка упрощенном
виде (без таблицы результатов), а заодно и русифицировать.
Код:
ПРОЦЕДУРА Стакан;
ПЕРЕМЕННЫЕ и:ЦЕЛЫЙ;
НАЧАЛО
ширина_канвы := запрос(ШИРИНА_КАНВЫ);
высота_канвы := запрос(ВЫСОТА_КАНВЫ);
цвет_фона(0);
прямоугольник(0, 0, ширина_канвы - 1, высота_канвы - 1);
ЦИКЛ_ДЛЯ и:=нач_у ДО кон_у +1 ДЕЛАТЬ
Кубик(5, и, цТемнозеленый);
Кубик(19, и, цТемнозеленый);
КОНЕЦ_ЦИКЛА;
ЦИКЛ_ДЛЯ и:=7 ДО 19 ДЕЛАТЬ
ЕСЛИ ((и ОСТАТОК 2) # 0) ТО
Кубик(и, кон_у+1, цТемнозеленый);
КОНЕЦ;
КОНЕЦ_ЦИКЛА;
содержимое_стакана;
КОНЕЦ Стакан;
ПРОЦЕДУРА одна_линия(нх,ну:ЦЕЛЫЙ; их,иу:ЛОГИЧЕСКИЙ);
ПЕРЕМЕННЫЕ
х, у, х1, у1, н_х, н_у, кол_повт,
тек_цв, цв, сх, су:ЦЕЛЫЙ;
НАЧАЛО
ЕСЛИ МассивИгры[ну][нх] >= цФлагЦвета ТО
тек_цв := МассивИгры[ну][нх] - цФлагЦвета;
ИНАЧЕ
тек_цв := МассивИгры[ну][нх];
КОНЕЦ;
кол_повт:=1; н_х:=нх; н_у:=ну;
сх:=1; ЕСЛИ ~ их ТО сх:=0; КОНЕЦ;
су:=1; ЕСЛИ ~ иу ТО су:=0; КОНЕЦ;
х:=нх+сх; у:=ну+су;
ЦИКЛ_ДО
ЕСЛИ МассивИгры[у][х] >= цФлагЦвета ТО
цв := МассивИгры[у][х] - цФлагЦвета;
ИНАЧЕ
цв := МассивИгры[у][х];
КОНЕЦ;
ЕСЛИ цв = тек_цв ТО УВЕЛИЧИТЬ(кол_повт); КОНЕЦ;
ЕСЛИ ( (цв # тек_цв) ИЛИ
((цв = тек_цв) & ((х=5) ИЛИ (у=разм))) ) &
(кол_повт >= 3) & (тек_цв # 0) ТО
х1:=н_х; у1:=н_у;
ЦИКЛ_ПОКА (х1 # х) ИЛИ (у1 # у) ДЕЛАТЬ
ЕСЛИ МассивИгры[у1][х1] < цФлагЦвета ТО
МассивИгры[у1][х1]:=МассивИгры[у1][х1]+цФлагЦвета;
КОНЕЦ;
ЕСЛИ их ТО УВЕЛИЧИТЬ(х1); КОНЕЦ;
ЕСЛИ иу ТО УВЕЛИЧИТЬ(у1); КОНЕЦ;
КОНЕЦ_ЦИКЛА;
ЕСЛИ цв = тек_цв ТО
ЕСЛИ МассивИгры[у][х] < цФлагЦвета ТО
МассивИгры[у][х]:= МассивИгры[у][х] + цФлагЦвета;
КОНЕЦ;
КОНЕЦ;
кол_очков:=кол_очков + кол_повт - 2;
КОНЕЦ;
ЕСЛИ цв # тек_цв ТО
кол_повт :=1; тек_цв :=цв; н_х :=х; н_у :=у;
КОНЕЦ;
ЕСЛИ их ТО УВЕЛИЧИТЬ(х); КОНЕЦ;
ЕСЛИ иу ТО УВЕЛИЧИТЬ(у); КОНЕЦ;
КОНЕЦ_ЦИКЛА_ДО (х > 5) ИЛИ (у > разм);
КОНЕЦ одна_линия;
ПРОЦЕДУРА подсчет_очков;
ПЕРЕМЕННЫЕ и, кол_очков_1, кол_очков_2:ЦЕЛЫЙ;
ПРОЦЕДУРА отражение_стакана;
ПЕРЕМЕННЫЕ и,д:ЦЕЛЫЙ;
НАЧАЛО
ЦИКЛ_ДЛЯ и:=1 ДО разм ДЕЛАТЬ
д:=МассивИгры[и][0];
МассивИгры[и][0]:=МассивИгры[и][5];
МассивИгры[и][5]:=д;
д:=МассивИгры[и][1];
МассивИгры[и][1]:=МассивИгры[и][4];
МассивИгры[и][4]:=д;
д:=МассивИгры[и][2];
МассивИгры[и][2]:=МассивИгры[и][3];
МассивИгры[и][3]:=д;
КОНЕЦ_ЦИКЛА;
КОНЕЦ отражение_стакана;
ПРОЦЕДУРА диагонали;
ПЕРЕМЕННЫЕ х,у:ЦЕЛЫЙ;
НАЧАЛО (* диагонали *)
(* возрастающие диагонали *)
ЦИКЛ_ДЛЯ х:=0 ДО 3 ДЕЛАТЬ
одна_линия(х,1,ДА,ДА); КОНЕЦ_ЦИКЛА;
ЦИКЛ_ДЛЯ у:=2 ДО разм-2 ДЕЛАТЬ
одна_линия(0,у,ДА,ДА); КОНЕЦ_ЦИКЛА;
(* убывающие диагонали *)
отражение_стакана;
ЦИКЛ_ДЛЯ х:=0 ДО 3 ДЕЛАТЬ
одна_линия(х,1,ДА,ДА); КОНЕЦ_ЦИКЛА;
ЦИКЛ_ДЛЯ у:=2 ДО разм-2 ДЕЛАТЬ
одна_линия(0,у,ДА,ДА); КОНЕЦ_ЦИКЛА;
отражение_стакана;
КОНЕЦ диагонали;
ПРОЦЕДУРА вертикали;
ПЕРЕМЕННЫЕ х:ЦЕЛЫЙ;
НАЧАЛО
ЦИКЛ_ДЛЯ х:=0 ДО 5 ДЕЛАТЬ
одна_линия(х,1,НЕТ,ДА); КОНЕЦ_ЦИКЛА;
КОНЕЦ вертикали;
ПРОЦЕДУРА горизонтали;
ПЕРЕМЕННЫЕ у:ЦЕЛЫЙ;
НАЧАЛО
ЦИКЛ_ДЛЯ у:=1 ДО разм ДЕЛАТЬ
одна_линия(0,у,ДА,НЕТ); КОНЕЦ_ЦИКЛА;
КОНЕЦ горизонтали;
ПРОЦЕДУРА удаление_блоков;
ПЕРЕМЕННЫЕ и,ж,макс,см,у:ЦЕЛЫЙ;
НАЧАЛО
ЦИКЛ_ДЛЯ и:=0 ДО 5 ДЕЛАТЬ
у:=1; см:=0; макс:=мх_мигр[и];
ЦИКЛ_ПОКА (у < макс) ДЕЛАТЬ
ЕСЛИ МассивИгры[у][и] >= цФлагЦвета ТО
ЦИКЛ_ДЛЯ ж:=у+1 ДО макс-1 ДЕЛАТЬ
МассивИгры[ж-1][и]:=МассивИгры[ж][и];
КОНЕЦ_ЦИКЛА;
МассивИгры[макс-1][и]:=0; УМЕНЬШИТЬ(макс);
ИНАЧЕ УВЕЛИЧИТЬ(у);
КОНЕЦ;
КОНЕЦ_ЦИКЛА;
см:=мх_мигр[и]-макс;
ЕСЛИ см # 0 ТО
у:=мх_мигр[и]-1;
ЦИКЛ_ДЛЯ ж:=мхту[и]+1 ДО кон_у ДЕЛАТЬ
(* вывод столбца *)
Кубик(хст[и], ж, МассивИгры[у][и]);
УМЕНЬШИТЬ(у);
КОНЕЦ_ЦИКЛА;
УМЕНЬШИТЬ(мх_мигр[и],см); УВЕЛИЧИТЬ(мхту[и],см);
КОНЕЦ;
КОНЕЦ_ЦИКЛА;
КОНЕЦ удаление_блоков;
НАЧАЛО
кол_очков_2:=кол_очков;
ЦИКЛ_ДО
кол_очков_1:=кол_очков;
разм:=мх_мигр[0];
ЦИКЛ_ДЛЯ и:=1 ДО 5 ДЕЛАТЬ
ЕСЛИ мх_мигр[и] > разм ТО разм:=мх_мигр[и]; КОНЕЦ;
КОНЕЦ_ЦИКЛА;
УМЕНЬШИТЬ(разм);
ЕСЛИ разм > 2 ТО диагонали; вертикали; КОНЕЦ;
горизонтали;
ЕСЛИ кол_очков_1 # кол_очков ТО удаление_блоков; КОНЕЦ;
КОНЕЦ_ЦИКЛА_ДО кол_очков_1 = кол_очков;
ЕСЛИ кол_очков_2 # кол_очков ТО
данные(ЧИСЛО_ОЧКОВ, кол_очков);
КОНЕЦ;
КОНЕЦ подсчет_очков;
Полные исходники проектов columns, kpdll и pasdll, а также
отредактированный файл ru.odc находятся в архиве columns.rar.
Предлагаемый способ программирования для среды BlackBox имеет, на
мой взгляд, следующие достоинства:
1) облегчается достижимость полной русификации исходного кода на КП по
сравнению с автономным BlackBox, т.к. сейчас типы и процедуры стандартных
модулей BlackBox имеют английские названия;
2) Вывод графики в Delphi проще, чем в BlackBox;
3) при отладке программы в Delphi появляется возможность использования
отладчика, пусть и не в пошаговом режиме.
Хотя в педагогическом смысле отладчик использовать вредно, но при
практическом программировании использование отладчика иногда помогает
отладить программу значительно быстрее, чем без него (особенно в состоянии
"смотришь в книгу - видишь фигу", иногда и такое бывает).
Для отладки программы в модуле u_columns задаем процедуру отладки
следующим образом:
Код:
type t_otladka = procedure(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10:integer);
type
Tf_column = class(TForm)
...
public:
otladka: t_otladka;
end;
var qq:integer;
procedure _otladka(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10:integer);
begin
if (a1 <> -1) then begin
...
end else begin
qq := 1; (* вызываем из FormCreate, чтобы можно было ставить
в этой процедуре точки останова *)
end;
end;
В FormCreate:
otladka := _otladka;
otladka(-1,0,0,0,0,0,0,0,0,0);
В модуле u_pasdll задаем экспортируемую процедуру:
procedure _otladka(n1,n2,n3,n4,n5,n6,n7,n8,n9,n10:integer);
begin
f1.otladka(n1,n2,n3,n4,n5,n6,n7,n8,n9,n10);
end;
В файле kpdll.txt:
ТИП
ПРОЦЕДУРА_10ПАР_ЦЕЛЫЙ = ПРОЦЕДУРА(п1,п2,п3,п4,п5,
п6,п7,п8,п9,п10:ЦЕЛЫЙ);
ПЕРЕМЕННЫЕ
отладка: ПРОЦЕДУРА_10ПАР_ЦЕЛЫЙ;
При вызове pasdll из kpdll:
отладка := S.VAL( ПРОЦЕДУРА_10ПАР_ЦЕЛЫЙ,
WinApi.GetProcAddress( dll, "_otladka" ) );
После чего можно отлаживаться, например:
ЦИКЛ_ПОКА (х1 # х) ИЛИ (у1 # у) ДЕЛАТЬ
ЕСЛИ МассивИгры[у1][х1] < цФлагЦвета ТО
МассивИгры[у1][х1]:=МассивИгры[у1][х1]+цФлагЦвета;
КОНЕЦ;
отладка(100, МассивИгры[у1][х1], у1, х1, 0,0,0,0,0,0);
ЕСЛИ их ТО УВЕЛИЧИТЬ(х1); КОНЕЦ;
ЕСЛИ иу ТО УВЕЛИЧИТЬ(у1); КОНЕЦ;
КОНЕЦ_ЦИКЛА;
ЕСЛИ цв = тек_цв ТО
ЕСЛИ МассивИгры[у][х] < цФлагЦвета ТО
МассивИгры[у][х]:= МассивИгры[у][х] + цФлагЦвета;
КОНЕЦ;
отладка(101, МассивИгры[у][х], у, х, 0,0,0,0,0,0);
КОНЕЦ;
Архив с файлами columns.rar :
Вложение:
columns.rar [65.14 КБ]
Скачиваний: 533