Автокликер Clickermann :: Форум

Основной раздел => Общие вопросы => Topic started by: Prorok.18 on May 19, 2015, 07:49:46 PM

Title: Случайный порядок
Post by: Prorok.18 on May 19, 2015, 07:49:46 PM
Есть число 18, надо выдать в лог числа от 1 до 18 в произвольном порядке
Title: Re: Случайный порядок
Post by: Oraven on May 19, 2015, 08:00:00 PM
Code: (clickermann) [Select]
IF(ARRSIZE($ARR) = 0)
   LOGWRITE ("Новый цикл")
   $count1 = 1 // начальное число
   $count2 = 18 // конечное число
   WHILE($count1 < $count2+1)
      ARRPUSH($ARR,$count1)
      INC($count1,1)
   END_CYC
END_IF
$ARR_SIZE = ARRSIZE($ARR)
FOR ($i=0, $i<$ARR_SIZE*2)
   $n1 = RND(0,$ARR_SIZE-1)
   $n2 = RND(0,$ARR_SIZE-1)
   $R = $ARR[$n1]
   $ARR[$n1] = $ARR[$n2]
   $ARR[$n2] = $R
END_CYC

$r = ARRPOP($ARR)
LOGWRITE ($r)
Title: Re: Случайный порядок
Post by: Prorok.18 on May 19, 2015, 08:17:46 PM
Работает отлично, понять бы еще, спс ;)
Умножать ARSIZE на 2 обязательно? Разброс ведь от этого не изменится, также? Сколько элементов в ARR столько и раз переставляем..
Title: Re: Случайный порядок
Post by: Vint on May 19, 2015, 09:23:42 PM
Обязательно будут повторы, сдвигая уже сдвинутые и не будет хватать количества обменов чтобы сдвинуть все числа с их стандартного места. Увеличивая число перестановок мы пытаемся задавить количеством. Приближаясь к совсем случайному.
Title: Re: Случайный порядок
Post by: Prorok.18 on May 20, 2015, 12:06:02 AM
Вот доказательство, домножать не надо
А повторов не было бы все равно, был бы меньший разброс и все, выходит его можно регулировать 8)

Code: (clickermann) [Select]
FOR($var,$var<18)
   IF(ARRSIZE($ARR) = 0)
      LOGWRITE ("Новый цикл")
      $count1 = 1 // начальное число
      $count2 = 18 // конечное число
      WHILE($count1 < $count2+1)
         ARRPUSH($ARR,$count1)
         INC($count1,1)
      END_CYC
   END_IF
   $ARR_SIZE = ARRSIZE($ARR)
   FOR ($i=0, $i<$ARR_SIZE)
      $n1 = RND(0,$ARR_SIZE-1)
      $n2 = RND(0,$ARR_SIZE-1)
      $R = $ARR[$n1]
      $ARR[$n1] = $ARR[$n2]
      $ARR[$n2] = $R
   END_CYC
   
   $r = ARRPOP($ARR)
   LOGWRITE ($r)
   ARRPUSH($ARR2,$r)
end_cyc


LOGWRITE("От min к max")

$min=$ARR2[0]
FOR($i=0,$i<ARRSIZE($ARR2))
   FOR($var=0,$var<ARRSIZE($ARR2)-$i)
      IF($ARR2[$var]<$min)
         $min=$ARR2[$var]
         $var2=$var
      END_IF
   END_CYC
   $ARR2[$var2]=$ARR2[ARRSIZE($ARR2)-1-$i]
   LOGWRITE($min)
   $min=$ARR2[0]+1
END_CYC
logshow(1)
halt
Title: Re: Случайный порядок
Post by: Vint on May 20, 2015, 06:27:06 AM
Тебе видней.
Повторы это и есть влияние на разброс, точнее перемешивание.
Прогони свой тест десяток раз и посмотри сколько в каждом чисел осталось на своих местах.
Например 5 на 5ом, 7 на 7ом, 16 на 16ом и т.д.

Если тебя это устраивает, не вопрос. В некоторых задачах это не гуд.
Title: Re: Случайный порядок
Post by: Vint on May 20, 2015, 02:34:51 PM
Вот доказательство, домножать не надо

Глянул с компа... Да доказательство железное  ;D

Говоришь не нужно перебирать 18* 2 раз, а сам делаешь 18 раз по 18. Как выгодно.
При этом в первом массиве остаётся всё меньше чисел, но переставляются они всё равно по 18 раз.
Осталось 3, 5 , 8 и 18 раз "тасуем".
Осталось 3, 8 ... ну понятно.
Title: Re: Случайный порядок
Post by: Prorok.18 on May 20, 2015, 08:34:35 PM
Ну 18 по 18 это перебор ;D, а в скрипте числа тасуются ровно столько раз, сколько их есть в массиве. Мешать еще не вижу смысла (мне это подсказывает интуиция и теория вероятности).
Кстати $ARR[$n2] можно не записывать, если кому надо ;)
Title: Re: Случайный порядок
Post by: Vint on May 21, 2015, 08:43:15 AM
Ну 18 по 18 это перебор ;D, а в скрипте числа тасуются ровно столько раз, сколько их есть в массиве. Мешать еще не вижу смысла (мне это подсказывает интуиция и теория вероятности).
Кстати $ARR[$n2] можно не записывать, если кому надо ;)

В теории вероятностей не силён, но хотелось бы взглянуть на выкладки.

P.S. Я невнимательно просмотрел пост Андрея. Увидев знакомые очертания я подумал о моём изначальном варианте перемешивания. Который выглядел примерно так:
Code: (clickermann) [Select]
IF(ARRSIZE($ARR) = 0)
   LOGWRITE ("Заполняем массив")
   $count1 = 1 // начальное число
   $count2 = 18 // конечное число
   WHILE($count1 < $count2+1)
      ARRPUSH($ARR,$count1)
      INC($count1,1)
   END_CYC
END_IF

$ARR_SIZE = ARRSIZE($ARR)
FOR ($i=0, $i<$ARR_SIZE*2)
   $n1 = RND(0,$ARR_SIZE-1)
   $n2 = RND(0,$ARR_SIZE-1)
   $R = $ARR[$n1]
   $ARR[$n1] = $ARR[$n2]
   $ARR[$n2] = $R
END_CYC

// вывод массива
$ARR_SIZE = ARRSIZE($ARR)
FOR ($i=0, $i<$ARR_SIZE)
   LOGWRITE ($ARR[$i])
END_CYC

HALT

Один раз создали массив, один раз перемешали (переставили элементы размер*2 раз) и по надобности извлекаем из массива готовые значения.

У Андрея же каждый раз перемешивается и извлекается по одному. В этом варианте (размер*2) конечно лишний и оправдан только на первой части вытащенных элементов. В итоге перестановок получилось даже больше чем 18*18   :D ;D    342 против 324
[spoiler]
Code: (clickermann) [Select]
IF(ARRSIZE($ARR) = 0)
   LOGWRITE (" Переставлено раз: ", $num)
   $num = 0
   LOGWRITE ("Новый цикл")
   $count1 = 1 // начальное число
   $count2 = 18 // конечное число
   WHILE($count1 < $count2+1)
      ARRPUSH($ARR,$count1)
      INC($count1,1)
   END_CYC
END_IF
$ARR_SIZE = ARRSIZE($ARR)
FOR ($i=0, $i<$ARR_SIZE*2)
   $n1 = RND(0,$ARR_SIZE-1)
   $n2 = RND(0,$ARR_SIZE-1)
   $R = $ARR[$n1]
   $ARR[$n1] = $ARR[$n2]
   $ARR[$n2] = $R
   INC($num)
END_CYC

$r = ARRPOP($ARR)
LOGWRITE ($r)
[/spoiler]

В моём варианте их всего 36

Вот если в моём изначальном не умножать на 2, в среднем 0-4 элемента остаются на своих старых местах по той же "интуитивной"  :) теории вероятностей.
Title: Re: Случайный порядок
Post by: Prorok.18 on May 21, 2015, 12:04:27 PM
Да и правда, в том скрипте без домножения элементы мешаются 18*19/2=171 раз ???, а я тут про 18 заганяю ;D
Вообщем вот
Code: (clickermann) [Select]
logclear
LOGWRITE ("Заполняем массив")
FOR($count,$count<18)
   ARRPUSH($ARR,$count+1)
END_CYC

$ARR_SIZE = ARRSIZE($ARR)
FOR ($i=0, $i<$ARR_SIZE*2)
   $n1 = RND(0,$ARR_SIZE-1)
   $n2 = RND(0,$ARR_SIZE-1)
   $R = $ARR[$n1]
   $ARR[$n1] = $ARR[$n2]
   $ARR[$n2] = $R
END_CYC

// вывод массива
WHILE(ARRSIZE($ARR)>0)
   LOGWRITE(ARRPOP($ARR))
END_CYC
logshow(1)
HALT
Title: Re: Случайный порядок
Post by: quant13 on May 24, 2015, 10:06:53 AM
Code: (Clickermann) [Select]
$n=18      //размер массива
UNDEFINE($arr)
LOGCLEAR
//создаем массив
FOR($count=0,$count<$n)
   ARRPUSH($ARR,$count+1)
END_CYC

//заполняем массив случайными числами без повторения
FOR($i=0,$i<($n-1))
   $j=rnd(1,$n)
   $tmp=$arr[$j]
   $arr[$j]=$arr[$i]
   $arr[$i]=$tmp
END_CYC

// вывод массива
WHILE(ARRSIZE($arr)>0)
   LOGWRITE(ARRPOP($arr))
END_CYC
HALT

Хотя в массиве случается попадается непонятный элемент, или просто пустой. Иногда, редко. Но из за этого иногда выдает ошибку выполнения, или в логе будет не число а пусто или загагулина какая-то. Не знаю откуда он берется и как избавится,

Добавлено. Избавился от пустого/странного элемента. Но теперь очень часто выдает ошибку интерпретации на строке $tmp=$arr[$j]. Пока разбираюсь. Хотя в целом оно работает, через раз, когда ошибки нет

Добавлено. Получается избавиться от ошибки если изменить строку
Code: (Clickermann) [Select]
//создаем массив
FOR($count=0,$count<($n+1))
но массив выйдет на 1 больше чем надо
Title: Re: Случайный порядок
Post by: Vint on May 25, 2015, 11:58:16 AM
Хотя в массиве случается попадается непонятный элемент, или просто пустой. Иногда, редко. Но из за этого иногда выдает ошибку выполнения, или в логе будет не число а пусто или загагулина какая-то. Не знаю откуда он берется и как избавится,

Исправлено. Избавился от пустого/странного элемента. Но теперь очень часто выдает ошибку интерпретации на строке $tmp=$arr[$j]. Пока разбираюсь. Хотя в целом оно работает, через раз, когда ошибки нет
Что там разбираться. Ты создал массив из 17 элементов. С индексами от 0 до 16.
(Кстати по условию было 18 элементов)

А в строке $tmp=$arr[$j], где $j  от 1 до 18 включительно (rnd(1,$n)).
Получается ты пытаешься прочитать элемент с индексом 1-18
Title: Re: Случайный порядок
Post by: quant13 on May 25, 2015, 12:11:40 PM
Code: (Clickermann) [Select]
$nm=18      //указываем размер массива
$n=$nm-1
UNDEFINE($arr)
LOGCLEAR
//создаем массив
FOR($count=0,$count<($n+1))
   ARRPUSH($ARR,$count+1)
END_CYC

//заполняем массив случайными числами без повторения
FOR($i=0,$i<($n-1))
   $j=rnd(1,$n)
   $tmp=$arr[$j]
   $arr[$j]=$arr[$i]
   $arr[$i]=$tmp
END_CYC

// вывод массива
WHILE(ARRSIZE($arr)>0)
   LOGWRITE(ARRPOP($arr))
END_CYC
HALT

так работает, хоть и не очень удобно для чтения
Title: Re: Случайный порядок
Post by: Vint on May 25, 2015, 12:15:31 PM
Добавлено. Получается избавиться от ошибки если изменить строку
Code: (Clickermann) [Select]
//создаем массив
FOR($count=0,$count<($n+1))
но массив выйдет на 1 больше чем надо

Ты чёт путаешся в индексах
$count<$n должно быть везде, без всяких -1

Иногда в результате у тебя получается 19 элементов из-за неправильной строки
Code: (clickermann) [Select]
$j=rnd(1,$n)это индексы и должны быть от 0 до 17
$j=rnd(0,$n-1)

И не "заполняем..." заполнил ты когда создал. Здесь перемешиваешь.

Должно быть так
Code: (clickermann) [Select]
$n=18      //размер массива
UNDEFINE($arr)
LOGCLEAR
//создаем массив
FOR($count=0,$count<$n)
   ARRPUSH($ARR,$count+1)
END_CYC

//перемешиваем
FOR($i=0,$i<$n-1)
   $j=rnd(0,$n-1)
   $tmp=$arr[$j]
   $arr[$j]=$arr[$i]
   $arr[$i]=$tmp
END_CYC

// вывод массива
WHILE(ARRSIZE($arr)>0)
   LOGWRITE(ARRPOP($arr))
END_CYC
HALT

Но по сути это те же яйца только сбоку. Там брали два случайных и меняли местами. Здесь пробегаем от первого до последнего и меняем со случайным.
Если случайное совпадёт с текущим, элемент останется на своём месте.
Title: Re: Случайный порядок
Post by: Atas on June 01, 2015, 07:37:51 PM
Всем привет! Рад видеть всех в добром здравии и в трудах праведных.  :)
Массивы это конечно здорово, но были же времена, когда обходились и без них. Вы просто забыли наверно, что сами писали полтора-два года тому назад, про псевдо массивы из строк с разделителями. Для работы со строками у Кликермана функций побольше, чем для массивов, по крайней мере пока. Я даже не рискну назвать эти функции костылями, применительно к этой задаче, просто они есть и они классные. И если бы такую тему подняли пару лет тому назад, то уверен, что никто бы так сильно не заморачивался и решение было бы примерно таким...
Code: (clickermann) [Select]
LOGCLEAR
$str = 0x010x020x030x040x050x060x070x080x090x0A0x0B0x0C0x0D0x0E0x0F0x100x110x12
FOR($i = 18, $i > 0, -1)
   $n = STRCUT($str, RND(1,$i) * 4 - 3, 4)
   $str = STRREPLACE($str, $n, "")
   LOGWRITE (INT($n))
END_CYC
HALT
Слава СОЗДАТЕЛЮ! :)
Title: Re: Случайный порядок
Post by: Vint on June 02, 2015, 09:35:29 AM
А такую тему и поднимали и тогда через строки и решали, только попроще... или посложней, в 10-ричном формате.
Предложенный тобой вариант намного изящней и компактней.

Вот вариант не такой изящный, конечно, но универсальней. А вдруг числа нужны не до 18, а до 50... или до 170?
Заманаемся $str = 0x010x020x..... подготавливать
Пусть сам заполняет  :D, правда для простоты в этом случае отойдём от 16-ричной системы.

Code: (clickermann) [Select]
LOGCLEAR
$count1 = 1 // начальное число
$count2 = 18 // конечное число
$str = ""
FOR($count = $count1-1, $count < $count2)
   $str = STRCONCAT($str, ":")
   FOR($i=0, $i < (3 - STRLEN($count+1)))
      $str = STRCONCAT($str, "0")
   END_CYC
   $str = STRCONCAT($str, $count+1)
END_CYC
//LOGWRITE ($str)
FOR($i = $count2, $i > 0, -1)
   $n = STRCUT($str, RND(1,$i) * 4 - 3, 4)
   $str = STRREPLACE($str, $n, "")
   LOGWRITE (INT(STRCUT($n, 2, 20)))
END_CYC
HALT
Title: Re: Случайный порядок
Post by: Atas on June 03, 2015, 11:46:12 AM
Благодарю за высокую оценку моего скромного труда.  :)  Тем более, что оценка авторитетная, поэтому вдвойне приятно. Спасибо. :)
В продолжение темы хочу представить на ваш суд еще один скрипт, теперь тоже более универсальный и простой.
Code: (clickermann) [Select]
LOGCLEAR

// На входе имеем массив из произвольных данных, для примера создадим его сами...
$arr[0] = "Audi R8 (4.2 FSI quattro AT) кабриолет 2012"
$arr[1] = "BMW i8 (362hp) купе 2013"
$arr[2] = "Ford Mustang 2.3 AT купе 2014"
$arr[3] = "Honda CR-V (1.6D AT 4WD) кроссовер 2015"
$arr[4] = "Mercedes-Benz GLE Coupe (350D AT) кроссовер 2015"

//--------------------------------

FOR($i = ARRSIZE($arr) - 1, $i > -1, -1) // Переменная "$i" это номер последней ячейки нашего входного массива
   
   $n = RND(0,$i) // Номер нужной ячейки массива, выбирается случайным образом из диапазона номеров оставшихся ячеек
   
   LOGWRITE ($arr[$n]) // Содержимое ячейки, которую мы выбрали случайным образом, выводим в лог
   
   // Теперь использованную ячейку нужно удалить из массива, чтобы не использовать ее повторно.
   // Но так как, на сегодняшний день, для удаления элемента массива мы располагаем только функцией "ARRPOP($arr)",
   // то пересохраняем содержимое последней (удаляемой) ячейки в позицию уже использованной и более ненужной ячейки с номером "$n".
   $arr[$n] = $arr[$i]
   
   ARRPOP($arr) // Последнюю ячейку массива теперь просто удаляем
   
END_CYC

HALT