Как проделать рандомайз?

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Пришла в голову дурная блажь повыпендриваться с 7-сегментными модулями на мах7219. Их шесть штук, в каждом по 8 разрядов. Что хочу: в хаотичном порядке заполнить все разряды всех модулей "восьмерками".  Понятно, что у нас для таких целей есть функция random(). Вот только, как сделать, чтобы в поисках случайного числа не участвовали уже зажженные разряды с "восьмеркой" - никак не допетрю. Дайте подсказку, ссылку, пояснение, (я уже совсем обнаглел) - скетчик...  Заранее благодарен!

Green
Offline
Зарегистрирован: 01.10.2015

Массив из 48-ми булевых переменных же? Или двухмерный 6х8 по вкусу?

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Green пишет:

Массив из 48-ми булевых переменных же? Или двухмерный 6х8 по вкусу?

Про массив того или иного вида - это понятно. Меня (видимо, был косноязычен) интересует процесс исключения из функции random () уже исполненных (зажженных) элементов массива. Вроде, рэндом в каждом очередном цикле все равно будет выбирать из исходного количества чисел. Тем самым, скорость заполнения табло станет заметно уменьшаться по мере зажигания все большего числа элементов. Или я не так рассуждаю?

Logik
Offline
Зарегистрирован: 05.08.2014

Можно конечно и на массиве с отметками уже зажженных элементов. По нему циклически бегает индекс. Генерим рандом 1-48 и перемещаем индекс на этот рандом, пропуская уже занятые. Но плохо, последние  элементы долго искать.

Есть и другой подход. Массив из 48 элементов заполняем последовательно значениями от 1 до 48. Рандомно генерим два номер элемента. И обмениваем их содержимое. Так повторяем пока не надоест. По сути массив перетасовывается. Далее в элементе 0 - номер первого зажигаемого разряда, в элементе 1 - номер следующего и так до конца.

Эта задача на собеседованиях встречается.  Первое решение считают не оптимальным.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

есть стандартный алгоритм перемешивания, называется std::random_shuffle. Исходники - открыты.

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Новый вопрос.  Вот простенький скетч:


#include <LedControl.h> //Загрузка библиотеки индикаторов на мах7219
//Пины управления индикацией
int pin_din_1=32; //Пин din цепочки №1
int pin_cs_1=30;  //Пин cs цепочки №1 
int pin_clk_1=28; //Пин clk цепочки №1
                  //GND цепочки №1
int pin_din_2=33; //Пин din цепочки №2 
int pin_cs_2=31;  //Пин cs цепочки №2
int pin_clk_2=29; //Пин clk цепочки №2
                  //GND цепочки №2 
//Cоздаём объекты класса LedControl [din,clk,cs,X)]четвертая цифра "X" - количество модулей. Управляем двумя цепочками модулей по 6 элементов
LedControl lc_1 = LedControl(pin_din_1, pin_clk_1, pin_cs_1, 6);
LedControl lc_2 = LedControl(pin_din_2, pin_clk_2, pin_cs_2, 6);
//Переменные теста индикации
int ind;
int dig;

void setup ()
{  //Выводим индикаторы из спящего режима
  for (ind=0;ind<6;ind++)
    {
      //Цепочка №1
      lc_1.shutdown(ind, false); //Выводим из спящего режима
      lc_1.setIntensity(ind,1);  //Яркость дисплея на 1. Всего возможных режимов яркости от 0 до 15
      lc_1.clearDisplay(ind);    //Очистить дисплей  
      //Цепочка №2
      lc_2.shutdown(ind, false); //Выводим из спящего режима
      lc_2.setIntensity(ind,1);  //Яркость дисплея на 1. Всего возможных режимов яркости от 0 до 15
      lc_2.clearDisplay(ind);    //Очистить дисплей      
    } 
  //Выравнивание яркости модулей индикаторов
  lc_1.setIntensity(0,5);
  lc_2.setIntensity(1,6);
  lc_2.setIntensity(5,5);
}  
void loop ()
{
  ind=random (6);
  dig=random (8);
  lc_1.setDigit (ind,dig,8,false); 
  delay (20);
}

И что я вижу? Каждый раз при запуске программы последовательность прописывания индикаторов одна и та же. Или я что-то не понимаю и делаю не так (скорее всего!) или где тогда произвольный выбор чисел?

sadman41
Offline
Зарегистрирован: 19.10.2016

randomSeed()

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

sadman41 пишет:
randomSeed()

Поставил вместо "random" "randomSeed". Гадость какую-то говорит компилятор: "void value not ignored as it ought to be". Перевел, но не понял: "Значение void не игнорируется, как надо". Если не трудно  - поправьте неверную строку.

sadman41
Offline
Зарегистрирован: 19.10.2016

Наверное надо посмотреть синтаксис, а не копипастить бездумно?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Да нету у ардуинки случайных чисел! 100500 раз обсуждалось. Хотите истинно случайное число - делайте его аппаратно на шумящих элементах.

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Содрал тупо с нашего сайта отсюда: http://arduino.ru/Reference/RandomSeed

Получилось:


#include <LedControl.h> //Загрузка библиотеки индикаторов на мах7219
//Пины управления индикацией
int pin_din_1=32; //Пин din цепочки №1
int pin_cs_1=30;  //Пин cs цепочки №1 
int pin_clk_1=28; //Пин clk цепочки №1
                  //GND цепочки №1
int pin_din_2=33; //Пин din цепочки №2 
int pin_cs_2=31;  //Пин cs цепочки №2
int pin_clk_2=29; //Пин clk цепочки №2
                  //GND цепочки №2 
//Cоздаём объекты класса LedControl [din,clk,cs,X)]четвертая цифра "X" - количество модулей. Управляем двумя цепочками модулей по 6 элементов
LedControl lc_1 = LedControl(pin_din_1, pin_clk_1, pin_cs_1, 6);
LedControl lc_2 = LedControl(pin_din_2, pin_clk_2, pin_cs_2, 6);
//Переменные теста индикации
int ind;
int dig;

void setup ()
{  //Выводим индикаторы из спящего режима
  for (ind=0;ind<6;ind++)
    {
      //Цепочка №1
      lc_1.shutdown(ind, false); //Выводим из спящего режима
      lc_1.setIntensity(ind,1);  //Яркость дисплея на 1. Всего возможных режимов яркости от 0 до 15
      lc_1.clearDisplay(ind);    //Очистить дисплей  
      //Цепочка №2
      lc_2.shutdown(ind, false); //Выводим из спящего режима
      lc_2.setIntensity(ind,1);  //Яркость дисплея на 1. Всего возможных режимов яркости от 0 до 15
      lc_2.clearDisplay(ind);    //Очистить дисплей      
    } 
  //Выравнивание яркости модулей индикаторов
  lc_1.setIntensity(0,5);
  lc_2.setIntensity(1,6);
  lc_2.setIntensity(5,5);
  randomSeed(0);

}  
void loop ()
{
  ind=random(6);
  dig=random(8);
  lc_1.setDigit (ind,dig,8,false); 

  delay (20);
}

Ничего не изменилось.

Logik
Offline
Зарегистрирован: 05.08.2014

Sonologist пишет:

Содрал тупо с нашего сайта отсюда

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

По вашему новому вопросу - random генерит псевдослучайное число из циклической последовательности некоторой. randomSeed сместит текущее положение в последовательности. 

-NMi-
Offline
Зарегистрирован: 20.08.2018

Sonologist пишет:

И что я вижу? Каждый раз при запуске программы последовательность прописывания индикаторов одна и та же. Или я что-то не понимаю ...........

Фсё-то ты панимашь, возможно даже и больше, чем надо. Вопросы твои всё больше и больше похожи на некий оччень тонкий глум форумный. Хотя вроде не школьнег......

А по поводу рандома - дык так оно и будет, ибо каждый раз дурдуина стартует по одному и тому-же сценарию.

Для того, чтобы изменить сценарий - нужно добавить ещё хотя-бы один элемент "рандомности" , например, время. И тогда всё будет так, как ты и хотел изначально  (задача поиска пустого горшка для тех, кому ..... срочно)                       ))))))))))))))))))))))))))))))))))))))))))))))))))

sadman41
Offline
Зарегистрирован: 19.10.2016

Щас миллис добавит...

Logik
Offline
Зарегистрирован: 05.08.2014

sadman41 пишет:
Щас миллис добавит...

)))

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Блин, мужики! Ну хорош меня пинать. Это не глум вовсе. Я - старый бэсиковод. Там в отличие от С (как я понимаю) рандомайз абсолютно честный: задал предел - и все: генерируется случайное число "от и до". Я ж не знал, что тут все по-другому. Рекомендуете миллис вставить. А что это даст? Миллис же будет тем же самым, то есть, последовательность  заполнения не изменится. Ну уж коль пошла такая пьянка, поправьте скетч, чтоб я понял, в чем затыка. А уж если к комментариями...

-NMi-
Offline
Зарегистрирован: 20.08.2018

Миллс нипамагёт, он так0же стартанёт вместе с процом ))))))))))))))))))))))))))))

Здеся надо чонить отдельное от ардуины - т.е. отдельные часы или ещё что отдельное... ну хоть фазу в электросети...

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

-NMi- пишет:

Миллс нипамагёт, он так0же стартанёт вместе с процом ))))))))))))))))))))))))))))

Здеся надо чонить отдельное от ардуины - т.е. отдельные часы или ещё что отдельное... ну хоть фазу в электросети...

То есть, если, скажем, один из выводов Ахххх висит в воздухе и болтается как говно в проруби, с него можно взять аналогрид, и от этого плясать?

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Все, проделал randomSeed с со свободного вывода А0. Сработало. Все спасибо, процесс понял.

-NMi-
Offline
Зарегистрирован: 20.08.2018

Дядько, ну раздэзь функцию рандома и сам всё поймёшь.

И по поводу ног аналоговых - напиши простую функцию вывода значений в сериал да посмотри на "аналоговую рандомность"  ))))))))

sadman41
Offline
Зарегистрирован: 19.10.2016

В примере с сайта как раз с А0 рэндомсид и делался.

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

sadman41 пишет:
В примере с сайта как раз с А0 рэндомсид и делался.

От он и сработал :)

SLKH
Offline
Зарегистрирован: 17.08.2015

Sonologist пишет:

Green пишет:

Массив из 48-ми булевых переменных же? Или двухмерный 6х8 по вкусу?

Про массив того или иного вида - это понятно. Меня (видимо, был косноязычен) интересует процесс исключения из функции random () уже исполненных (зажженных) элементов массива. Вроде, рэндом в каждом очередном цикле все равно будет выбирать из исходного количества чисел. Тем самым, скорость заполнения табло станет заметно уменьшаться по мере зажигания все большего числа элементов. Или я не так рассуждаю?

насчет "заметно" - есть сомнения. вычисления "чё надо зажечь" гораздо быстрее, чем последовательный вывод в мах7219.  

-NMi-
Offline
Зарегистрирован: 20.08.2018

А хто мешат замутить асинхронную функцию и считать "наперёд" в отдельный массив?

Чото типа вывод синхронизировать по таймеру или любому другому событию а массив вычислять "наперёд" , разделив функцию на несколько коротких итераций?   Не???

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Вот тебе твоя игрушка на JS. Посмотреть можно на любом онлайн редакторе или в броузере открыть, сохранив как .html файл. Можно на  https://js.do скопипастив туда.

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <link href="styles/style.css" rel="stylesheet" type="text/css">
    <title>Случайный порядок</title>
</head>

<body>
    <canvas width="400" height="300"></canvas>
    <script>
        var canvas = document.querySelector("canvas");
        var context = canvas.getContext("2d");
        context.fillStyle = "red";
        context.strokeStyle = "black";
        context.lineWidth = 2;
        function D7(x, y, cx,w=36,h=36,l=8) {
            this.x = x;
            this.y = y;
            this.w = w;
            this.h = h;
            this.l = l;
            this.context = cx;
            this.show = function (...ii) {
                for (i=0; i< ii.length; i++) {
                    switch (ii[i]) {
                        case 1: this.context.fillRect(x + l + 1, y, w - 2 * l - 2, l); break;
                        case 2: this.context.fillRect(x + w - l, y, l, h - 1); break;
                        case 3: this.context.fillRect(x + w - l, y + h + 1, l, h - 1); break;
                        case 4: this.context.fillRect(x + l + 1, y + 2 * h - l, w - 2 * l - 2, l); break;
                        case 5: this.context.fillRect(x, y + h + 1, l, h - 1); break;
                        case 6: this.context.fillRect(x, y, l, h - 1); break;
                        case 7: this.context.fillRect(x + l + 1, y + h - l / 2, w - 2 * l - 2, l); break;
                        case 8: this.context.fillRect(x + w + 1, y + 2 * h - l, l, l); break;
                    }
                }
            }
        }

        d7a = new Array(6);
        for (i = 0; i < 6; i++) {
            d7a[i] = new D7(30+i*46,30 , context);
        }

        seg = new Array(48);
        for (i=0; i<48;i++) seg[i] = i;
        for (i = 47; i > 0; i--) {
            j = Math.floor(Math.random() * (i + 1)); 
            tmp = seg[i]; seg[i] = seg[j]; seg[j] = tmp;
        }

        var iii = 0;
        function mySt () {
            d7a[Math.floor(seg[iii]/8)].show(seg[iii]%8+1);
            iii++; 
            if (iii > 48) iii=0;
        }
        tId = setInterval(mySt,100);
        setTimeout(() => { clearInterval(tId); }, 4900);
    </script>
</body>
</html>