Инструменты пользователя

Инструменты сайта


help:dynamical

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Both sides previous revision Предыдущая версия
Следущая версия
Предыдущая версия
help:dynamical [2013/11/05 18:52]
newsash
help:dynamical [2024/10/14 12:17] (текущий)
aleks_versus
Строка 1: Строка 1:
 [[help:​service_locations|Назад:​ Служебные локации]] [[help:​service_locations|Назад:​ Служебные локации]]
-=====Динамический код===== 
-DYNAMIC [$строка кода],​[параметр 1],​[параметр 2], ... - выполнение кода. Данный оператор позволяет динамически генерировать код игры. Переданные параметры хранятся в массиве ARGS. После выполнения кода предыдущие значения ARGS восстанавливаются. Примеры:​ 
  
-DYNAMIC '$a="​string<<​$b>>"'​ +====== Динамический код ======
-DYNAMIC '​$a'​ +
-DYNAMIC 'if $a="​string":''​text!'''​ +
-DYNAMIC " +
-$args[0] +
-addobj $args[1] +
-",'​Текст','​Вилка'+
  
-DYNEVAL([$выражение],​[параметр 1],[параметр 2], ...) - возвращает значение ​указанного выражения. Функция позволяет вычислять значения динамически сгенерированных выражений. Указанные параметры передаются в массиве ARGS, а после вычисления выражения предыдущие значения ARGS восстанавливаются. Примеры:​ +===== Лирическое вступление, поясняющее, для чего ​может пригодиться динамический код =====
-DYNEVAL('​3+4'​) +
-PL DYNEVAL('​mid("​abcd",​2,​1)+"​qwerty"'​) +
-PL DYNEVAL($test + ' + val("<<​$test>>"​)'​) +
-проход=DYNEVAL("​ $args[0] <> '​текст'​ ", '​строка'​)+
  
 +Из-за своей линейности язык **QSP** лишён некоторых плюшек,​ которые есть в других языках программирования. Например,​ если вам нужно вывести на печать массив,​ вы делаете это с помощью цикла:
  
 +<sxh qsp>
 +! массив mass создан заранее
 +loop local i,​size=0,​arrsize('​mass'​) while i<size step i+=1:
 +  *pl mass[i]
 +end
 +</​sxh>​
 +
 +Но, что если вам нужно вывести на печать десять массивов?​ Писать на каждый массив по циклу?
 +
 +Гораздо проще написать одну универсальную локацию-функцию (см. раздел [[help:​organizing|"​Пользовательские функции и процедуры"​]]),​ передавать в неё название массива и выводить одним и тем же циклом на печать любой массив.
 +
 +И вот для этого нам потребуется использовать динамический код.
 +
 +(на самом деле у этой задачи есть решение и без применения оператора ''​%%DYNAMIC%%'',​ но сейчас нас интересует именно динамический код, поэтому продолжим в рамках нужного для примера решения).
 +
 +Динамический код — это код, который мы не знаем заранее. Мы пишем лишь его составные части, а уже при выполнении программы этот код составляется из этих частей в нужные комбинации.
 +
 +Прежде всего стоит спросить себя, из чего состоит любой код? И, кажется,​ что ответ очевиден:​ код состоит из команд. Это верно, но чем по сути являются команды?​ А вот тут ответ очевиден не для всех: команды — это строки текста.
 +
 +Мы с вами прекрасно умеем работать со строками. Если не умеем, то быстренько читаем раздел [[help:​strings|"​Строки"​]] и учимся.
 +
 +Строки можно склеивать,​ в них можно встраивать подвыражения,​ из них можно вырезать фрагменты. Вот и с кодом, по сути, можно делать то же самое. Так давайте запишем наш цикл в виде строки:​
 +
 +<sxh qsp>
 +"loop local i,​size=0,​arrsize('​mass'​) while i<size step i+=1:
 +  *pl mass[i]
 +end"
 +</​sxh>​
 +
 +Что мы тут видим? А видим мы, что в этой строке прописано название массива ''​%%mass%%'',​ аж целых два раза. Название массива — это значение,​ которое можно помещать в перемнную,​ а можно извлекать из переменной.
 +
 +Например,​ мы поместили название массива в переменную ''​%%$array_name%%''​. Как нам вставить значение этой переменной в наш код, записанный в виде строки?​ Используем подвыражения:​
 +
 +<sxh qsp>
 +$array_name='​mass'​
 +"loop local i,​size=0,​arrsize('<<​$array_name>>'​) while i<size step i+=1:
 +  *pl <<​$array_name>>​[i]
 +end"
 +</​sxh>​
 +
 +Если мы запустим получившуюся локацию,​ мы увидим на экране наш цикл с массивом **mass**. Если мы пропишем в переменную ''​%%$array_name%%''​ название другого массива,​ и снова запустим локацию,​ мы увидим на экране тот же цикл, но с другим массивом. Это значит,​ что наша строка текста формируется **динамически**!
 +
 +Получается,​ и код цикла формируется динамически. Нам осталось только научиться запускать на выполнение такой код, записанный в виде строки текста.
 +
 +И вот для этого, как раз, в **QSP** есть специальный оператор:​ ''​%%DYNAMIC%%''​. Мы просто передаём этому оператору наш записанный в виде текста цикл, и оператор ''​%%DYNAMIC%%''​ легко его выполняет,​ как обычный код QSP:
 +
 +<sxh qsp>
 +$array_name='​mass'​
 +dynamic "loop local i,​size=0,​arrsize('<<​$array_name>>'​) while i<size step i+=1:
 +  *pl <<​$array_name>>​[i]
 +end"
 +</​sxh>​
 +
 +Таким образом,​ заменяя значение в переменной ''​%%$array_name%%'',​ мы легко выводим на печать любой массив. А чтобы нам было ещё проще, мы создаём специальную локацию-функцию,​ и ей, в качестве аргументов,​ будем передавать названия массивов,​ которые хотим распечатать. Назовём эту локацию ''​%%print_array%%'':​
 +
 +<sxh qsp>
 +!# print_array
 +dynamic "loop local i,​size=0,​arrsize('<<​$args[0]>>'​) while i<size step i+=1:
 +  *pl <<​$args[0]>>​[i]
 +end"
 +</​sxh>​
 +
 +И теперь,​ как мы выведем на печать любой, какой хотим, массив?​ Проще простого:​
 +
 +<sxh qsp>
 +@print_array('​mass'​)
 +@print_array('​$unit_name'​)
 +@print_array('​unit_count'​)
 +</​sxh>​
 +
 +Вот так возможность работы с динамическим кодом позволяет нам сделать наш код QSP более гибким и легко читаемым.
 +
 +===== DYNAMIC =====
 +
 +''​%%DYNAMIC%%''​ — выполняет код, переданный в виде строки текста. Общая запись:​
 +
 +<sxh qsp>
 +DYNAMIC [$код],​[аргумент 0],​[аргумент 1], ... ,​[аргумент 18]
 +</​sxh>​
 +
 +, где ''​%%[$код]%%''​ — это обычный код QSP, записанный в виде текста. Выполнение такого кода аналогично выполнению кода оператора ''​%%GOSUB%%''​. Аргументы ''​%%[аргумент 0]%%'',​ ''​%%[аргумент 1]%%''​ и т.д. могут использоваться внутри ''​%%[$код]%%'',​ их значения автоматически помещаются в ячейки массива ''​%%args%%'':​ в ''​%%ARGS[0]%%'',​ ''​%%ARGS[1]%%'',​ и т.д. соответственно. Внутри выполняемого кода ''​%%DYNAMIC%%''​ используется свой собственный массив ''​%%ARGS%%'',​ его значения не пересекаются со значениями ''​%%ARGS%%''​ на локации,​ из которой ''​%%DYNAMIC%%''​ был вызван. После выполнения кода, переданного оператору ''​%%DYNAMIC%%'',​ продолжается выполнение кода со следующей команды после ''​%%DYNAMIC%%''​.
 +
 +Примеры:​
 +
 +<sxh qsp>
 +! простые вызовы кода, записанного в виде текста
 +dynamic '​$a="​string<<​$b>>"'​
 +dynamic '​$a'​
 +dynamic 'if $a="​string":''​text!'''​
 +! вызов кода с передачей в него аргументов
 +dynamic "
 +  *pl $args[0]
 +  addobj $args[1]
 +",'​Вы взяли вилку.','​Вилка'​
 +</​sxh>​
 +
 +Нижеследующая информация справедлива и для функции ''​%%DYNEVAL%%''​ (см. ниже).
 +
 +**Важно!** Если код задан с помощью одинарных (''​%%'​ '​%%''​) или двойных (''​%%"​ "​%%''​) кавычек,​ подвыражения вычисляются сразу:
 +
 +<sxh qsp>
 +$args[0]='​qwerty'​
 +$code = '
 +  *pl "<<​$args[0]>>"​
 +  *pl $args[0]
 +'
 +
 +dynamic $code,'​asdfg'​
 +</​sxh>​
 +
 +В этом случае при задании переменной **$code** будет вычислено подвыражение,​ поэтому когда ''​%%DYNAMIC%%''​ выполнит код, первой строкой выведется '​qwerty',​ второй строкой выведется '​asdfg'​.
 +
 +Фигурные скобки - третий вид кавычек используемый специально для написания динамического кода. Здесь поддерживается вложенность скобок,​ а подвыражения не вычисляются:​
 +
 +<sxh qsp>
 +$args[0]='​qwerty'​
 +$code = {
 +  *pl "<<​$args[0]>>"​
 +  *pl $args[0]
 +}
 +
 +dynamic $code,'​asdfg'​
 +</​sxh>​
 +
 +В этом случае будут выведены две строки '​asdfg'​. Так как подвыражение не вычисляется на момент присвоения кода переменной **$code**, но зато будет вычислено уже при непосредственном выполнении кода оператором ''​%%DYNAMIC%%''​.
 +
 +===== DYNEVAL =====
 +
 +''​%%DYNEVAL%%''​ — выполняет код, переданный в виде строки текста,​ и возвращает результат,​ если он есть. Общая запись:​
 +
 +<sxh qsp>
 +$DYNEVAL([$код],​[аргумент 0],​[аргумент 1], ... ,​[аргумент 18])
 +DYNEVAL([$код],​[аргумент 0],​[аргумент 1], ... ,​[аргумент 18])
 +</​sxh>​
 +
 +, где ''​%%[$код]%%''​ — это обычный код QSP, записанный в виде текста. Выполнение такого кода аналогично выполнению кода функции ''​%%FUNC%%''​. Аргументы ''​%%[аргумент 0]%%'',​ ''​%%[аргумент 1]%%''​ и т.д. могут использоваться внутри ''​%%[$код]%%'',​ их значения автоматически помещаются в массив ''​%%ARGS%%'',​ в ячейки ''​%%ARGS[0]%%'',​ ''​%%ARGS[1]%%'',​ и т.д. соответственно. Внутри выполняемого кода ''​%%DYNEVAL%%''​ используется свой собственный массив ''​%%ARGS%%'',​ его значения не пересекаются со значениями ''​%%ARGS%%''​ на локации,​ из которой ''​%%DYNEVAL%%''​ была вызвана. После выполнения кода, переданного функции ''​%%DYNEVAL%%'',​ продолжается вычисление выражения,​ в котором расположена функция ''​%%DYNEVAL%%''​.
 +
 +Чтобы ''​%%DYNEVAL%%''​ возвращала результат,​ необходимо внутри ''​%%[$код]%%''​ присвоить этот результат переменной ''​%%RESULT%%''​.
 +
 +Примеры:​
 +
 +<sxh qsp>
 +dyneval('​result = 3+4')
 +*pl $dyneval('​$result = $mid("​abcd",​2,​1)+"​qwerty"'​)
 +проход = dyneval("​result = ($args[0] <> '​текст'​)",​ '​строка'​)
 +</​sxh>​
 +
 +  * Чтобы ''​%%DYNEVAL%%''​ вернула строковое значение,​ результат должен быть записан в ''​%%$RESULT%%''​.
 +  * Чтобы ''​%%DYNEVAL%%''​ вернула числовое значение,​ результат должен быть записан в ''​%%RESULT%%''​.
 +  * Чтобы ''​%%DYNEVAL%%''​ вернула несколько значений,​ результат нужно записать в ''​%%%RESULT%%''​ как кортеж значений.
 +  * ''​%%%RESULT%%'',​ ''​%%$RESULT%%''​ и ''​%%RESULT%%''​ — это одна и та же переменная,​ но с разными типами данных. **Следует помнить**,​ что новая запись значения затирает предыдущее,​ какого бы типа данных не было это значение.
 +
 +Если при выполнении ''​%%DYNEVAL%%''​ она не возвращает значения (''​%%RESULT%%''​ не инициализируется),​ и является единственным элементом выражения,​ передаваемого неявному оператору,​ плеер ничего не выведет на экран. Т.е. ''​%%DYNEVAL%%''​ будет работать,​ как ''​%%DYNAMIC%%''​. Пример:​
 +
 +<sxh qsp>
 +! неявный оператор выведет на экран 123:
 +123
 +! код в dyneval выполнится,​ но на экране
 +! мы ничего не увидим:​
 +dyneval("​code = 123 + 890")
 +! неявный оператор выведет на экран 1013:
 +code
 +</​sxh>​
 +
 +===== Области применения DYNAMIC и DYNEVAL =====
 +
 +''​%%DYNAMIC%%''​ и ''​%%DYNEVAL%%''​ следует использовать в нескольких случаях:​
 +
 +  * Когда нет иного способа получить необходимый функционал. Как пример,​ очень распространённый случай генерации действий с помощью цикла: <sxh qsp>
 +loop i=1 while i<=10 step i+=1:
 +  act "​Действие <<​i>>":​ *pl "​Действие <<​i>>"​
 +end
 +</​sxh>​ В данном случае будут созданы действия с названиями "​Действие 1" ... "​Действие 10". Неопытный автор ожидает,​ что каждое из этих действий при щелчке по нему будет выводить собственный номер. Однако,​ это ожидание не верно. Переменная ''​%%i%%''​ в данном случае получит значение **10**, и в момент выполнения действия именно это значение подставится в строку,​ выводимую на экран. То есть подвыражение,​ относящееся к коду действия,​ не будет раскрыто плеером,​ пока игрок не кликнет по действию.\\
 +Чтобы действительно сгенерировать действия,​ которые будут выводить свой правильный номер, раскрытие подвыражения должно происходить в момент создания действия. Как раз для этого и подойдёт оператор ''​%%DYNAMIC%%'':​ <sxh qsp>
 +loop i=1 while i<=10 step i+=1:
 +  dynamic 'act "​Действие <<​i>>":​ *pl "​Действие <<​i>>"'​
 +end
 +</​sxh>​ В этом случае сначала раскроются подвыражения,​ а затем готовый код будет передан оператору ''​%%DYNAMIC%%''​. Таким образом сформируются дейстия с уже готовым уникальным кодом действия.
 +  * Также ''​%%DYNAMIC%%''​ и ''​%%DYNEVAL%%''​ очень удобны,​ когда нужно выполнить некоторый многострочный код в том месте, где невозможно разместить такой многострочный код. Например,​ в гиперссылках:​ <sxh qsp>
 +$CODE = {
 +  if no деньги<​100:​
 +    addobj '​Кружка имбирного эля'​
 +    кружка_эля+=1
 +    деньги-=100
 +    *pl "Я приобрёл куржку имбирного эля."​
 +  else
 +    *pl "​Мне не хватает денег на эль."​
 +  end
 +}
 +*pl "<a href='​exec:​dynamic $CODE'>​Купить кружку имбирного эля</​a>"​
 +</​sxh>​ В этом случае переменная ''​%%$CODE%%''​ обязательно должна быть глобальной,​ иначе ссылка её не "​увидит"​. Однако,​ если необходимо использовать такой код в условиях или циклах,​ вполне можно обойтись и локальной переменной,​ чтобы код не висел в памяти:​ <sxh qsp>
 +! этот код не имеет практической пользы. Просто для примера.
 +local $code = {
 +  if args[0]+args[1]+args[2]+args[3]=0:​
 +    result=1
 +  elseif args[0]+args[1]+args[2]+args[3]=4:​
 +    result=1
 +  else:
 +    result=0
 +  end
 +}
 +loop while dyneval($code,​a,​b,​c,​d):​
 +  a = rand(0,1)
 +  b = rand(0,1)
 +  c = rand(0,1)
 +  d = rand(0,1)
 +end
 +</​sxh>​ В своём роде это способ создавать анонимные функции в QSP.
 +  * Ещё ''​%%DYNAMIC%%''​ очень удобен для разного рода [[help:​debugger|отладчиков]],​ поскольку позволяет выполнять код QSP, введённый в строку ввода безо всяких танцев с бубном.
 +  * ''​%%DYNAMIC%%''​ позволяет восстанавливать действия,​ полученные с помощью функции ''​%%$CURACTS%%'',​ и предметы,​ полученные с помощью функции ''​%%$CUROBJS%%'':​ <sxh qsp>
 +$acts = $curacts
 +cla
 +dynamic $acts
 +</​sxh>​
 +
 +Нет смысла использовать динамический код, если вы можете получить тот же результат без его использования. Прежде чем всюду пихать ''​%%DYNAMIC%%''​ хорошенько подумайте,​ а не целесообразнее было бы написать этот код на отдельной локации так, чтобы не приходилось использовать ''​%%DYNAMIC%%''​. Динамический код сложнее читать и на него сложнее ссылаться. Он в принципе ухудшает читаемость кода.
 +
 +Вполне возможно вложение динамического кода в динамический код, то есть ''​%%DYNAMIC%%''/''​%%DYNEVAL%%''​ внутри ''​%%DYNAMIC%%''/''​%%DYNEVAL%%'',​ однако это мало того, что ухудшает читаемость,​ так ещё и очень часто приводит к багам, которые трудно отловить. Банально,​ неверная закрытая кавычка внутри кода внутри кода может вызвать ошибку,​ выбиваемую вообще не понятно в какой строке локации. Тем не менее число вложений не ограничено.
 +
 +[[help:​menu|Вперёд:​ Всплывающее меню]]
  
help/dynamical.1383677536.txt.gz · Последние изменения: 2013/11/05 22:52 (внешнее изменение)