Содержание

Генераторы случайных чисел

Если когда-нибудь пытались написать свой Тетрис, сделать электронную свечку или собрать светомузыку — точно использовали случайные числа. Пара строк кода и программа уже выдаёт новую фигурку или яркость светодиода. Всё просто?

На самом деле нет. Компьютер штука умная, но предельно логичная. Выполнить сложную программу, обработать тысячи чисел за долю секунды — никаких проблем, но придумать действительно случайное число компьютер не может. Все «случайные» числа это результат выполнения заранее написанной программы. Поэтому правильнее называть их псевдослучайными.

ТехноБайка: случайны ли случайные числа и как обыграть казино

Стандартная функция генерации псевдослучайных чисел

В проектах на Arduino для получения псевдослучайного числа предусмотрена функция random(). В параметрах функции можно задать диапазон получаемых значений, от минимального до максимального.

random.ino
long randNumber;
 
void setup(){
  Serial.begin(9600);
}
 
void loop() {
  randNumber = random(1000);    // выбираем случайное число от 0 до 999
  Serial.println(randNumber);   // выводим число в Serial Port
 
  delay(1000); // ждём одну секунду
}

Если вы запустите этот скетч, увидите, что после каждого перезапуска платы последовательность чисел будет повторяться. Чтобы последовательность не повторялась, необходимо запустить генератор случайных чисел со случайным параметром. Для этого предусмотрена функция randomSeed(). В качестве параметра функции зададим номер свободного аналогового пина. Шум с него инициализирует генератор случайных чисел.

random-seed.ino
long randNumber;
 
void setup(){
  Serial.begin(9600);
  randomSeed(analogRead(0));
}
 
void loop() {
  randNumber = random(10, 100);
  Serial.println(randNumber);
  delay(1000);
}

Автомат для игры «Орёл и Решка»

Это самый простой игровой автомат. Arduino Uno, пара светодиодов и тактовая кнопка. Нажимаете кнопку — случайным образом загорается один из светодиодов: или красный, или зелёный. Угадали какой загорится, можно подавать заявку на участие в «Битве экстрасенсов».

В проекте использовались:

orlanka.ino
// подключим библиотеку для работы с кнопками
#include <TroykaButton.h>
 
// Пины светодиодов
#define LRED    8
#define LGREEN  10
// Пин кнопки
#define BUTTON  6
 
// создаем объект класса TroykaButton
TroykaButton but(BUTTON);
 
unsigned long timer = 0;
 
void setup() {
  // определяем пины как входы/выходы
  pinMode (LRED, OUTPUT);
  pinMode (LGREEN, OUTPUT);
  pinMode (BUTTON, INPUT_PULLUP);
  // инициализируем последовательность случайных чисел
  randomSeed(analogRead(A3));
  // инициализируем кноку
  but.begin();
}
 
void loop() {
  // считываем значение кнопки
  but.read();
  // было ли короткое нажатие?
  if (but.isClick())
  {
    // задаем случайное значение для "монеты"
    int coin = random(2);
    // проверяем, что за значение:
    if (coin) {
      // если 1, то зеленый светодиод горит 1 секунду
      timer = millis();
      while (millis() - timer < 1000) {
        digitalWrite(LGREEN, HIGH);
      }
      digitalWrite(LGREEN, LOW);
    } else {
      // если 0, то красный светодиод горит 1 секунду
      timer = millis();
      while (millis() - timer < 1000) {
        digitalWrite(LRED, HIGH);
      }
      digitalWrite(LRED, LOW);
    }
  }
}

Автомат «Три семёрки»

Игровой автомат генерирует трёхзначное число. Если всецифры в нём совпали — Bingo! Если нет, попробуйте свою удачу ещё раз.

Игровой автомат собран в образовательных целях. Использовать подобные устройства для получения прибыли запрещено законами Российской Федерации.

В проекте использовались:

777.ino
// Подключаем библиотеку для работы с дисплеем
#include <QuadDisplay2.h>
#include <TroykaButton.h>
// Пин для пищалки
#define BUZZER 4
// Пин для кнопки
#define BUTTON 6
// Пин для дисплея
#define QUADDISPLAY 10
 
// ноты для мелодий
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
 
// Номер октавы
#define OCTAVE 2
 
// Длительность таймера
#define CLOCK 1000
 
// создаем объект класса QuadDisplay и передаем номер пина CS
QuadDisplay qd(QUADDISPLAY);
// создаем объект для работы с кнопкой с параметром номер пина
TroykaButton button(BUTTON);
 
// создаем флаг для кнопки
bool buttonFlag = true;
// создаем объект класса long для хранения счетчика времени
unsigned long timer;
 
// создаем массив для хранения цифр дисплея
const uint8_t digits[] = {QD_0, QD_1, QD_2, QD_3, QD_4, QD_5, QD_6, QD_7, QD_8, QD_9};
// создаем массив с анимацией ожидания
const uint8_t animated[] = {0b11111011, 0b11110111, 0b11101111, 0b11011111, 0b10111111, 0b01111111, 0b11111011};
 
// создаем массив с нотами для стартовой мелодии
int startTune[] = {NOTE_C4, NOTE_C4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_C5};
// создаем массив с длительностями нот для стартовой мелодии
int durationStartTune[] = {100, 100, 100, 300, 100, 300};
 
// создаем массив с нотами для мелодии победы
int gameWin[] = {NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_G4, NOTE_F4, NOTE_E4, NOTE_F4, NOTE_G4};
// создаем массив с длительностями нот для мелодии победы
int durationGameWin[] = {100, 200, 100, 200, 100, 400, 100, 100, 100, 100, 200, 100, 500};
 
void setup() {
  // инициализируем дисплей
  qd.begin();
  // инициализируем кноку
  button.begin();
}
 
void loop() {
  // запускаем цикл воспроизводящий надпись "Play", которая прерывается нажатием кнопки
  timer = millis();
  buttonFlag = !buttonFlag;
  while (millis() - timer < CLOCK) {
    if (buttonFlag) {
      qd.displayDigits(QD_P, QD_L, QD_A, QD_Y);
    } else {
      qd.displayClear();
    }
    // считываем значение кнопки
    button.read();
    // было ли короткое нажатие?
    if (button.isClick()) {
      // создаем массив символов для отображения выпавшего числа
      uint8_t value[] = {QD_NONE, QD_NONE, QD_NONE};
      // воспроизводим стартовую мелодию
      melody(startTune, durationStartTune, sizeof(startTune) / sizeof(int));
      // запускаем функцию генерации случайного числа
      bandit(value);
      // воспроизводим анимацию
      cartoon(value);
 
      if (value[0] == value[1] && value[1] == value[2] && value[0] == value[2]) {
        melody(gameWin, durationGameWin, sizeof(gameWin) / sizeof(int));
      } else {
        if (value[0] == value[1] || value[1] == value[2] || value[0] == value[2]) {
          melody(gameWin, durationGameWin, 4);
        }
      }
      buttonFlag = true;
    }
  }
}
 
// функция, которая генерирует случайное число
void bandit(uint8_t value[]) {
  randomSeed(analogRead(A3));
  // инициализируем последовательность случайных чисел
  for (int i = 0; i < 3; i++) {
    // записываем случайные числа в массив
    value[i]  = digits [random(0, 9)]; 
  }
}
 
// функция, которая воспроизводит анимацию показа числа на дисплее
void cartoon (uint8_t value[]) {
  for (int j = 0; j <= 4; j++) {
    for (int i = 0; i < (sizeof (animated) / sizeof(uint8_t)); i++) {
      timer = millis();
      while (millis() - timer < (CLOCK / 20)) {
        switch (j) {
          case 0: {
              qd.displayDigits (animated[i], animated[i], animated[i], QD_NONE);
              break;
            }
          case 1: {
              qd.displayDigits (value[0], animated[i], animated[i], QD_NONE);
              break;
            }
          case 2: {
              qd.displayDigits (value[0], value[1], animated[i], QD_NONE);
              break;
            }
          case 3: {
              qd.displayDigits (value[0], value[1], value[2], QD_NONE);
              break;
            }
        }
      }
    }
  }
}
 
// функция воспроизведения мелодий
void melody(int melody[], int noteDurations[], int noteCount)
{
  // Играем мелодию
  for (int thisNote = 0; thisNote < noteCount; thisNote++) {
    tone(BUZZER, OCTAVE * melody[thisNote]);
    delay(noteDurations[thisNote]);
    noTone(BUZZER);
  }
}