Author Topic: Не работают вложенные циклы FOR, выполняются нелогично.  (Read 9009 times)

0 Members and 1 Guest are viewing this topic.

BashOrgRu

  • Зашел в гости
  • *
  • Posts: 6
    • View Profile
Привет ещё раз всем. Вчера до 3х ночи пытался заставить заработать вложенные циклы.

Задача такая:

Персонаж должен копать (работает) N раз (работает) после этого класть материалы в багажник (работает) и снова начинать копать (не работает).
Сейчас скрипт ведёт себя так: запускает саб с внутренним циклом FOR (копает N раз (вынес это в отдельный SUB(pickaxe_use), 12я строка)), после этого запускает внешний цикл и $cnt_cycles раз сбрасывает груз в багажник, игнорируя копку.

Не работало даже при использовании самого простого варианта с
Code: [Select]
FOR($x, $x < 3)
 FOR($y, $y < 3)
  print($x, ":", $y)
 END_CYC
END_CYC
Вело себя абсолютно так же.
А по логике, каждый раз, когда внутренний цикл отработал (накопал), он должен продолжить внешний цикл (там саб сбросить в багажник), и начать внешний цикл заново, проникнуть во внутренний и запустить копание. Вместо этого копание срабатывает только один раз, остальные разы он просто $cnt_cycles раз сбрасывает груз в багажник

Code: (clickermann) [Select]
#ps2_keyboard //Без этого параметра игра не воспринимает нажатые кнопки

DEFINE($cnt_a, 10) //КОЛИЧЕСТВО АЙТЕМОВ ДЛЯ СБРОСА
DEFINE($cnt_runs, 5) //Количество запусков копки до сброса
DEFINE($cnt_cycles, 2) //Количество циклов копка-сброс
   
SUB(clocker_a) // Звук по завершении копки.
   WAITMS(50)
   SOUND("Notify.wav")
END_SUB

SUB(pickaxe_use) //Саб на копание
FOR($a,$a<$cnt_runs) //Копаем $cnt_runs раз
WAITMS(20)
KEYPRESS(#Y) //Открыть меню игрока Y
    WAITMS(200)
    MOVE(820,260)
    WAITMS(100)
    LCLICK(820,260) //Выбрать кирку
    WAITMS(100)
    MOVE(830,530)
    WAITMS(100)
    LCLICK(830,530) //Нажать использовать
    WAITMS(50)
    WAITMS(7800)  //Ожидание чуда (конца одного раза копки)
  END_CYC
END_SUB

SUB(throw_to_truck) //Бросить в багажник
KEYPRESS(#T) //Открыть багажник
WAITMS(50)
MOVE(710,283) //Move to second thing
    WAITMS(100)
    LCLICK(710,283)
    WAITMS(50)
    MOVE(720,540) //Сдвинуться в текстовое поле
    WAITMS(100)
    LCLICK(720,540)
WAITMS(50)
KEYPRESS(8)
WAITMS(50)
KEYSTRING($cnt_a)  //Изменение количества айтемов в поле
    WAITMS(100)
    LCLICK(790,585) //Положить
WAITMS(50)
KEYPRESS(27) //Нажать ESC чтобы закрыть меню
END_SUB

//Меня интересует это место:
IF(iskeydown(#O)=1) //Инициация скрипта

FOR($b,$b<$cnt_cycles) //Считаем циклы для полной загрузки грузовика
pickaxe_use() //Этот саб копает N раз (внутри цикл FOR)
WAITMS(20)
throw_to_truck() //Выбрасываем в грузовик
END_CYC
clocker_a() //Конец работы, звук
END_IF

Где собака?
« Last Edit: November 01, 2014, 12:34:11 PM by BashOrgRu »

Atas

  • Активный участник
  • ***
  • Posts: 147
    • View Profile
[spoiler=FOR (цикл с параметром) - Цитата из справки Clickermann v4.11 (build 000)]

Синтаксис

FOR ($var, expression, [step]) ... END_CYC - организует цикл с параметром

Параметры
$var - переменная, которая будет наращиваться на значение step после каждой итерации цикла (параметр цикла)
expression - логическое выражение, при истинности которого выполняется тело цикла (см. IF)
step - значение шага, на которое каждую итерацию увеличивается переменная; необязательный параметр

Описание
Существует возможность инициализировать переменную в заголовке цикла через знак "=". Например

for ($i = 5, $i < 10)
...
Если переменная до выполнения цикла уже была инициализирована (в том числе в этом же цикле на прошлом прогоне скрипта), то цикл начнется с использованием текущего значения переменной. Если это "новая" переменная, она будет инициализирована нулем.
Перед каждым выполнением итерации (тела цикла) проверяется условие expression и если оно истинно, то тело цикла выполняется, в противном случае цикл завершается. После каждой итерации параметр цикла автоматически увеличивается на step. Если значение опущено (необязательный параметр), что считается что step = 1.

Пример

// простой пример с минимумом данных
for($var, $var < 5)
 logwrite("var: ", $var)
end_cyc

// с инициализацией параметра
for($var=5, $var < 10)
 logwrite("var: ", $var)
end_cyc

// с инициализацией параметра и заданным шагом
for($var=10, $var < 100, 10)
 logwrite("var: ", $var)
end_cyc

// пример с вложенным циклом
FOR($x, $x < 3)
 FOR($y, $y < 3)
  print($x, ":", $y)
 END_CYC
END_CYC

// пример с комплексным условием
$y=0

FOR($x, ($y < 10)&($x < 10) )
 print("x:",$x," y:",$y)
 inc($y, 5)
END_CYC
[/spoiler]
Вот эти два условия должны выполняться, чтобы всё работало.
Code: (clickermann) [Select]
FOR($a,$a<$cnt_runs) //Копаем $cnt_runs раз
   //
END_CYC

FOR($b,$b<$cnt_cycles) //Считаем циклы для полной загрузки грузовика
   //
END_CYC

// Переменные $a и $b, после использования их в циклах,
// изменяются до такой степени, что условие выполнения цикла становится
// невозможным и цикл завершается.
// Для того, чтобы запустить цикл еще раз,
// необходимо ичменить значения этих переменных, например удалить их из памяти.

UNDEFINE($a)
UNDEFINE($b)
« Last Edit: November 01, 2014, 01:55:08 PM by Atas »

BashOrgRu

  • Зашел в гости
  • *
  • Posts: 6
    • View Profile
Блинский блин! Вот я так и думал, что нужно было обнулять эти переменные!
Сейчас попробую и расскажу!
Спасибо большое!

UPD
Да, теперь скрипт отлично работает!
Спасибо за объяснение!
« Last Edit: November 01, 2014, 01:03:47 PM by BashOrgRu »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
кстати в версии 4.10 твой скрипт будет работать нармально(скорее всего)

BashOrgRu

  • Зашел в гости
  • *
  • Posts: 6
    • View Profile
А, а у меня версия 4.11 .
Я просто думал, что после исполнения цикла FOR его переменная обнуляется.

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
Цикл FOR не обнуляет индекс, если он (индекс) уже был инициализирован ранее

это исправление для версии 4.11

Atas

  • Активный участник
  • ***
  • Posts: 147
    • View Profile
Еще пару слов об оптимизации кода...
Дело в том, что выполняя этот скрипт, Clickermann делает много лишней работы.
Строки с 1 по 47 достаточно было бы прочитать один раз, а строки начиная с 50-й уже крутить в цикле.
Так что, надо думать как это реализовать, но без использования GOTO, иначе папки тапками закидают. :)
« Last Edit: November 01, 2014, 02:00:51 PM by Atas »

BashOrgRu

  • Зашел в гости
  • *
  • Posts: 6
    • View Profile
Как у вас тут всё серьезно.)) Спасибо.

У меня вообще вопрос, можно ли испoльзовать просто LCLICK(координаты) без MOVE()?

Oraven

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3685
  • Котэ
    • View Profile
У меня вообще вопрос, можно ли испoльзовать просто LCLICK(координаты) без MOVE()?
Можно, однако в отдельных случаях (флеш) нужно чтобы курсор сначала навелся а потом нажал иначе не работает.

Да теперь писать надо так
Code: (clickermann) [Select]
FOR($x=0, $x < 3)
 FOR($y=0, $y < 3)
  print($x, ":", $y)
 END_CYC
END_CYC

И подпрограммы тут лишние
Code: (clickermann) [Select]
#ps2_keyboard //Без этого параметра игра не воспринимает нажатые кнопки

DEFINE($cnt_a, 10) //КОЛИЧЕСТВО АЙТЕМОВ ДЛЯ СБРОСА
DEFINE($cnt_runs, 5) //Количество запусков копки до сброса
DEFINE($cnt_cycles, 2) //Количество циклов копка-сброс

//Меня интересует это место:
IF(iskeydown(#O)=1) //Инициация скрипта
   FOR($b=0,$b<$cnt_cycles) //Считаем циклы для полной загрузки грузовика
      FOR($a=0,$a<$cnt_runs) //Копаем $cnt_runs раз
         WAITMS(20)
         KEYPRESS(#Y) //Открыть меню игрока Y
         WAITMS(200)
         MOVE(820,260)
         WAITMS(100)
         LCLICK(820,260) //Выбрать кирку
         WAITMS(100)
         MOVE(830,530)
         WAITMS(100)
         LCLICK(830,530) //Нажать использовать
         WAITMS(7800)  //Ожидание чуда (конца одного раза копки)
      END_CYC
      WAITMS(20)
      KEYPRESS(#T) //Открыть багажник
      WAITMS(50)
      MOVE(710,283) //Move to second thing
      WAITMS(100)
      LCLICK(710,283)
      WAITMS(50)
      MOVE(720,540) //Сдвинуться в текстовое поле
      WAITMS(100)
      LCLICK(720,540)
      WAITMS(50)
      KEYPRESS(8)
      WAITMS(50)
      KEYSTRING($cnt_a)  //Изменение количества айтемов в поле
      WAITMS(100)
      LCLICK(790,585) //Положить
      WAITMS(50)
      KEYPRESS(27) //Нажать ESC чтобы закрыть меню
      WAITMS(50)
   END_CYC
   WAITMS(50)
   SOUND("Notify.wav") //Конец работы, звук
ELSE
   WAITMS(20)
END_IF
« Last Edit: November 01, 2014, 02:38:49 PM by Oraven »

Kubus

  • Зашел в гости
  • *
  • Posts: 10
    • View Profile
Друзья, подскажите где чего нужно поправить, что бы цикл заработал как раньше. В 4.10 все гуд.

Code: (clickermann) [Select]
$cykles = 0
$cykles_all = 1
$kora_s_x = 1
$kora_s_y = 1
$x = 0
$y = 0

print(" кори x:y   ",$kora_s_x," : ",$kora_s_y)
while($cykles<$cykles_all)      /// скільки сегментів буде пройдено *Х разів
   FOR($x, ($x<$bazs_x))  //  скільки  по Х пройдено секторів
      FOR($y,($y<$bazs_Y))  ////  скільки  по у  пройдено секторів
         print(" кори x:y   ",$kora_s_x," : ",$kora_s_y)
         $kora_s_y=5*$Ry+$kora_s_y  //приріст по У
      END_CYC
      $Ry = -1 * $Ry                   // розворот по У при зміні Х
      $kora_s_x = $kora_s_x +$Rx*5     // приріст по Х
   END_CYC
   inc($cykles)
END_CYC
все крутилось на ура. Теперь прочитав изложеные выше посты не могу понять куда чего нужно вставить для воскрешения периодичной цикличности.
« Last Edit: March 02, 2015, 06:52:31 PM by Oraven »

Oraven

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3685
  • Котэ
    • View Profile
цикл FOR теперь не обнуляет переменную, нужно добавить один параметр если это требуется.
FOR($x=0, $x<$bazs_x)

Code: (clickermann) [Select]
$cykles = 0
$cykles_all = 1
$kora_s_x = 1
$kora_s_y = 1
$x = 0
$y = 0

print(" кори x:y   ",$kora_s_x," : ",$kora_s_y)
while($cykles<$cykles_all)      /// скільки сегментів буде пройдено *Х разів
   FOR($x=0, $x<$bazs_x)  //  скільки  по Х пройдено секторів
      FOR($y=0,$y<$bazs_Y)  ////  скільки  по у  пройдено секторів
         print(" кори x:y   ",$kora_s_x," : ",$kora_s_y)
         $kora_s_y=5*$Ry+$kora_s_y  //приріст по У
      END_CYC
      $Ry = -1 * $Ry                   // розворот по У при зміні Х
      $kora_s_x = $kora_s_x +$Rx*5     // приріст по Х
   END_CYC
   inc($cykles)
END_CYC
« Last Edit: March 02, 2015, 06:54:09 PM by Oraven »

Kubus

  • Зашел в гости
  • *
  • Posts: 10
    • View Profile
Спасибо за быстрый ответ, но проблема осталась... Если  Вас не затруднит - помогите мне и другим пользователям решить эту простую задачку. Пришлось понатыкать команд вывода в лог, сами Видите что попало в обработку. Сам не могу понять в чем дело, вроде как простой и частый пример использования.
Code: [Select]
// Скрипт для тестів
// Author: Михайло
// Version: 3.1 (02.03.2015)
//

$cykles = 0
$cykles_all = 1
$kora_s_x = 1
$kora_s_y = 1


print("вхід x:y   ",$kora_s_x," : ",$kora_s_y)

while($cykles<$cykles_all)      /// скільки сегментів буде пройдено *Х разів
   print("while x:y   ",$kora_s_x," : ",$kora_s_y)
   
for($x=0,$x<$bazs_x)  //  скільки  по Х пройдено секторів
      print("по Х x:y   ",$kora_s_x," : ",$kora_s_y)
     
for($y=0,$y<$bazs_Y)  ////  скільки  по у  пройдено секторів
         print("по У x:y   ",$kora_s_x," : ",$kora_s_y)
         
         $kora_s_y=5*$Ry+$kora_s_y  //приріст по У
      END_CYC
     
$Ry = -1 * $Ry                   // розворот по У при зміні Х
      $kora_s_x = $kora_s_x +$Rx*5     // приріст по Х
   
END_CYC
   inc($cykles)
END_CYC

print("Кінець скрипта")

//halt // for single run

вот и протокол выполнения.
[spoiler]
23:02:22 вхід x:y   1 : 1
23:02:22 while x:y   1 : 1
23:02:22 Кінець скрипта

[/spoiler]

Kubus

  • Зашел в гости
  • *
  • Posts: 10
    • View Profile
Спасибо, пример начал вращаться.Удачи Вам !!!