RU

Пример создания циклов с помощью DYNAMIC.

Axil #1339 04.02.2015 18:52 17 comments 12072 views

Хочу поделиться секретом, как делать удобные циклы.
В какой-нибудь локации которая инициализируется в начале прописываем нужные варианты циклов как динамический код:
Например, простой цикл по i и двойной по y и x.

$FOR_i={
i = args[0]
:labelloop_i
if i <= args[1]:
  dynamic $args[3]
  i+=args[2]
  jump 'labelloop_i'
end
}

$FOR_xy={
y = args[0]
:labelloopxy_y
if y <= args[1]:
  x = args[3]
  :labelloopxy_x
  if x <= args[4]:
    dynamic $args[6]
    x+=args[5]
    jump 'labelloopxy_x'
  end
  y+=args[2]
  jump 'labelloopxy_y'
end
}

Для простого цикла аргументы: начальное значение i, конечное значение i(включительно), шаг приращения i, код
Используем простой цикл по i:

dynamic $FOR_i, 0, 9, 1, _
{
  *pl i
}

Используем вложенный цикл:

dynamic $FOR_xy, 0, 10, 2, 0, 5, 1, _
{
  *pl "(<<x>>,<<y>>)"
}

Либо, если нужны еще какие-то действия в конце внутренего цикла - то используем два простых цикла по X и Y:

dynamic $FOR_y, 0, 9, 1, _
{
  dynamic $FOR_x, 0, 9, 1, _
  {  
    *p "(<<x>>,<<y>>)"
  }
  *pl
}

Все очень просто. Становится похоже на С++.
Но есть недостаток - из  не сделать jump наружу, тоесть не прервать цикл раньше времени.

Edited at 04.02.2015 18:53 (11 years ago)

Рискну предложить некоторое усовершенствование первого (простого) варианта:

$FOR_i = {
	i = args[0]
	step = 1
	if ARGS[2]: step = ARGS[2] 
	:labelloop_i
	if (i <= ARGS[1] and step > 0) or (i >= ARGS[1] and step < 0):
		dynamic $args[3] 
		i += step
		jump 'labelloop_i' 
	end
}
Aleks Versus Moderator 04.02.2015 18:52 (11 years ago)

Не пойму, зачем вы суёте в переменные код, который можно тиснуть на отдельной локации и вызывать через gosub.

Aleks Versus:

Не пойму, зачем вы суёте в переменные код, который можно тиснуть на отдельной локации и вызывать через gosub.

По тому что использовать локацию не так удобно. Текст локации будет плохо читаться из-за if elseif.
Это примерно как на обычном языке программирования испрользовать вообще одну функцию для всего, а внутри напихать кучу всяких условий. Так делать можно, но это будет говнокодом.
По тому что dynamic гибче, agrs[] для него свои собственные, а не единые на всю локацию.
По тому что динамический код можно написать не в отдельной локации, а по ходу выполнения другого кода.
По тому что dynamic внутри dynamic нормально работать будет, а через локации - не уверен.

Переместил обсуждение в отдельную тему.

Aleks Versus Moderator 05.02.2015 05:55 (11 years ago)

Axil:

По тому что использовать локацию не так удобно. Текст локации будет плохо читаться из-за if elseif…

Не понимаю.

Axil:

По тому что dynamic гибче, agrs[] для него свои собственные, а не единые на всю локацию.

Не понимаю.

Axil:

По тому что динамический код можно написать не в отдельной локации, а по ходу выполнения другого кода.

Да, но ты говоришь:

Axil:

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

И ещё

Axil:

dynamic внутри dynamic нормально работать будет, а через локации - не уверен.

Для этого конкретного кода всё будет работать.
У меня возникло чувство, что мы по-разному понимаем локации.

Кажется я понял что ты не понимаешь. Ты предагаешь каждую функцию, каждый цикл с данном случае, запихнуть в отдельную локацию? Я же думал о другом варианте - локация одна, но в ней разные функции, которые разделены условиями по первому аргументу. Тоесть:
GS ‘functions’, ‘FOR_i’, 0, 9, 0
GS ‘functions’, ‘FOR_x’, 0, 9, 0
А в локации functions:
if $args[0] = ‘FOR_i’:
* * *
elseif $args[0] = ‘FOR_x’:
* * *
end
И это было-бы действительно нечитаемо и неудобно.

Но ты кажется предлогаешь делать под каждую функцию свою локацию? Так и количества локаций может не хватить и искать их неудобно. Я понимаю что физически это все один файл, но все равно воспринимаю каждую локацию как отдельный файл, ну привык думать как для обычных языков программирования.

Тут как и везде должна быть золотая середина. Все в одной локации это одна крайность. Сотни локаций под одну функию - это другая крайность. А вот завести одну локацию под часто повторяющийся динамический код - это и есть середина.

Aleks Versus Moderator 06.02.2015 18:41 (11 years ago)

Axil,
а вон в чём дело. Забить ВСЕ циклы в переменные. Извиняюсь, неверно прочитал техническое задание. Я почему-то подумал об универсальном цикле, который потом можно использовать в любом месте игры. А ты предлагаешь просто разгрузить от повторения одинаковых по структуре циклов. Об универсальном речи не шло. Лады, согласен, способ удобный.
Теперь по коду. Не проще ли так?:

$for_i={args[0] = args[0] 
:labelloop_i 
if args[0] <= args[1]: 
  dynamic $args[3],args[0],args[1],args[2]
  args[0]+=args[2] 
  jump 'labelloop_i' 
end}

Вызов:

dynamic $for_i,0,9,1,{
*pl args[0]
}
Aleks Versus Moderator 06.02.2015 18:53 (11 years ago)

Кстати по прерыванию цикла. Выполнение динамического кода прекрасно прерывается командой exit.
Пример:

$forONE={args[9] = args[9] & ! чтоб не потерять аргументы 
:labelloop_i 
if args[0] <= args[1]: 
  $args['result']=$dyneval($args[3],args[0],args[1],args[2])
  if $args['result']='exit': $result=$args['result'] & exit
  args[0]+=args[2] 
  jump 'labelloop_i' 
end}

вызов:

dynamic $forONE,0,9,1,'if args[0]=5: $result="exit" else *pl args[0]'

Если фантазия позволяет, при использовании $dyneval при вызове цикла можно заставить его прыгать и на метку, и на локацию.

Жаль, что мне не хватило времени довести новую версию до релиза - там уже почти готовы нормальные циклы и локальные переменные.

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

dynamic $FOR, 'название переменной-счетчика', начальное значение счетчика, конечное значение счетчика, шаг,{
		операторы в теле цикла
}

Цикл for-next

$FOR = { 
    dynamic '<<$ARGS[0]>> = <<ARGS[1]>>
    :labelloop_<<$ARGS[0]>>
    if (<<$ARGS[0]>> <= <<ARGS[2]>> and <<ARGS[3]>> > 0) or (<<$ARGS[0]>> >= <<ARGS[2]>> and <<ARGS[3]>> < 0): 
        <<$ARGS[4]>>
        <<$ARGS[0]>> += <<ARGS[3]>>
        jump "labelloop_<<$ARGS[0]>>"
    end
    <<$ARGS[0]>> -= <<ARGS[3]>>'
}

Поддерживается вложенность.
Пример использования:

dynamic $FOR, 'i', 0, 10, 1, {
	*nl i
}

Вложенные циклы:

dynamic $FOR, 'i', 5, 10, 1, {
	dynamic $FOR, 'j', 9, 2, -3, {
		*nl '<<i>> <<j>>'
	}
}

Можно использовать и в виде отдельной локации и вызывать через gs. Это дело вкуса.

Не исключаю возможные грабли. Было бы хорошо, если бы Nex прокомментировал.

evp,
мне хватает обычных циклов, без DYNAMIC.

А в следующей версии QSP циклы будут встроены. Так что не вижу особой необходимости что-то изобретать.

Мне не пригодится, но, может быть, кому-то другому это будет полезно.

Если бы была известна дата выхода новой версии, то изобретать не было бы необходимости.

Nex, я , вообще-то, хотел от вас услышать комментарии по ограничениям этого способа. Например, какой уровень вложенности dynamic и, соответственно, вложенных циклов допустим?

я , вообще-то, хотел от вас услышать комментарии по ограничениям этого способа

Так бы сразу и спросил :)
evp,

Максимальная вложенность выражений: 30

Ограничения QSP

Впрочем, если содержимое фигурных скобок рассматривается как особая символьная строка (что вполне вероятно), то ограничение вложенности не должно действовать. Я так не вспомню, это нужно смотреть в исходниках интерпретатора, либо спрашивать у Байта.

Log in or Register to post comments.