#define NUM_BUTTONS 4
#define VOLUME 10 // 0-30
#include <Wire.h>
#include "LiquidCrystal_I2C.h"
#include "DFRobotDFPlayerMini.h"
// библиотека для эмуляции Serial порта
#include <SoftwareSerial.h>
// создаём объект mySoftwareSerial и передаём номера управляющих пинов RX и TX
// RX - цифровой вывод 10, необходимо соединить с выводом TX дисплея
// TX - цифровой вывод 11, необходимо соединить с выводом RX дисплея
SoftwareSerial mySoftwareSerial(11, 12); // RX, TX для плеера DFPlayer Mini
DFRobotDFPlayerMini myDFPlayer;
LiquidCrystal_I2C lcd(0x27,16,2); // Устанавливаем дисплей
// Минимальная ставка в рублях
int minPlayBet = 10;
// Средняя ставка в рублях
int betweenPlayBet = 20;
// Максимальная ставка в рублях
int maxPlayBet = 30;
// Определение пина для подключения сигнала монетоприёмника
const int coinInput = 13;
// Переменная для хранения суммы в рублях
volatile long totalAmount = 100;
// Переменная для хранения суммы ставки в рублях
int totalBet = 0;
// Настройки вероятностей
const int PROBABILITY_SAME_ALL = 50; // Вероятность того, что все три числа одинаковы (в %)
const int PROBABILITY_11_NEARBY = 15; // Вероятность того, что две единицы будут рядом (в %)
void displayBetNowToMatrix() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(String("Credits: ") + String(totalAmount));
lcd.setCursor(0, 1);
lcd.print(String("Bet: ") + String(totalBet));
}
void minLoseBet() {
totalAmount -= totalBet;
displayBetNowToMatrix();
}
// Функция прерывания для подсчёта денег
void countMoney() {
totalAmount += 1; // Добавляем 1 рубль за каждый импульс
if (totalAmount >= minPlayBet) {
displayBetNowToMatrix();
} else {
lcd.setCursor(0, 1);
lcd.print(String("Credits: ") + String(totalAmount) + String(" rub."));
}
}
// Пины подключения светодиодов
const int redPin[] = {2, 4, 6};
const int bluePin[] = {3, 5, 7};
const int greenPin[] = {8, 9, 10};
const int buttonPins[] = {A0, A1, A2, A3}; // Пины, к которым подключены кнопки
int buttonStates[NUM_BUTTONS]; // Текущие состояния кнопок
int lastButtonStates[NUM_BUTTONS]; // Последние известные состояния кнопок
const unsigned long debounceDelay = 50; // Время защиты от дребезга (миллисекунды)
// Переменная для хранения времени начала вращения
unsigned long startTime = 0;
// Время мигания светодиодов перед остановкой
const unsigned long spinDuration = 3000; // 5 секунд
// Вероятность выигрыша (в процентах) (не используется, новая вероятность выше в коде)
//float winProbability = 0.03f; // 0.50f = 50% шанс выигрыша, 0.044% = 0.44%
// Массив для хранения выигрышных комбинаций (Не используется, комбинации хранятся в функции startGame())
//const char* winningCombinations[] = {"BBB", "RRR", "GGG", "RRG", "RRB", "GRR", "BRR"}; // Для человека: 🔴🔴🔴, 🔵🔵🔵, 🟢🟢🟢, 🔴🔴
//const char* winningCombinationsBetween[] = {"RRR", "RBG"}; // Для человека: 🔴🔴🔴, 🔴🔴
//const char* winningCombinationsMax[] = {"BBB", "RR"}; // Для человека: 🔵🔵🔵, 🔴🔴
// Выигрыши за комбинации в минимальной ставке
long firstCombM = 5000;
long secondCombM = 5000;
long thirdCombM = 1500;
long fourthCombM = 100;
// Выигрыши за комбинации в средней ставке
long firstCombB = 7000;
long secondCombB = 200;
// Выигрыши за комбинации в средней ставке
long firstCombS = 10000;
long secondCombS = 400;
int randomCombination;
int lastResult;
// Количество светодиодов в каждой группе
const int numRedLEDs = sizeof(redPin) / sizeof(int);
const int numBlueLEDs = sizeof(bluePin) / sizeof(int);
const int numGreenLEDs = sizeof(greenPin) / sizeof(int);
// Флаги состояния светодиодов (true - включен, false - выключен)
bool ledState[numRedLEDs];
bool ledStateBlue[numBlueLEDs];
bool ledStateGreen[numGreenLEDs];
// Время начала мигания
unsigned long startBlinkTime = 0;
// Интервал мигания (в миллисекундах)
const unsigned long blinkInterval = 500;
// Длительность мигания (в миллисекундах)
const unsigned long blinkDuration = 3500;
bool clickOneCollect = false;
void setup() {
lcd.init();
lcd.backlight();// Включаем подсветку дисплея
mySoftwareSerial.begin(9600);
Serial.begin(9600);
delay(1000);
Serial.println();
Serial.println("DFPlayer Mini Demo");
Serial.println("Initializing DFPlayer...");
if (!myDFPlayer.begin(mySoftwareSerial)) {
Serial.println("Unable to begin:");
Serial.println("1.Please recheck the connection!");
Serial.println("2.Please insert the SD card!");
while (true);
}
Serial.println(F("DFPlayer Mini online."));
myDFPlayer.setTimeOut(300);
//----Set volume----
myDFPlayer.volume(VOLUME); //Set volume value (0~30).
//----Set different EQ----
myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
myDFPlayer.play(1); //Воспроизведение первого mp3
lcd.print("Wait, init...");
delay(5000);
myDFPlayer.play(7);
lcd.clear();
lcd.print(String("Min bet: ") + String(minPlayBet) + String(" rub."));
// Настраиваем пин монетоприёмника как вход
pinMode(coinInput, INPUT);
// Настраиваем прерывание на пине 2 (каждый раз при изменении состояния пина)
attachInterrupt(digitalPinToInterrupt(coinInput), countMoney, FALLING);
Serial.begin(9600);
// Настройка пинов светодиодов как выходов
for (int i = 0; i < 3; ++i) {
pinMode(redPin[i], OUTPUT);
pinMode(bluePin[i], OUTPUT);
pinMode(greenPin[i], OUTPUT);
}
for (int i = 0; i < NUM_BUTTONS; i++) {
pinMode(buttonPins[i], INPUT_PULLUP); // Используем встроенные подтягивающие резисторы
buttonStates[i] = LOW;
lastButtonStates[i] = LOW;
}
}
void loop() {
for (int i = 0; i < NUM_BUTTONS; i++) {
// Считываем текущее состояние кнопки
buttonStates[i] = digitalRead(buttonPins[i]);
// Проверяем, изменилось ли состояние кнопки
if (buttonStates[i] != lastButtonStates[i]) {
if (buttonStates[i] == HIGH) { // Кнопка была нажата
if (i == 0) {
// SPIN
if (totalAmount == 0) {
myDFPlayer.play(3);
Serial.println("Not enough money!");
} else {
if (totalAmount >= minPlayBet) {
if (totalBet <= totalAmount) { // Проверка достаточно ли денег на ставку
if (totalBet == 0) {
Serial.println("Please enter a bet!");
myDFPlayer.play(4);
} else {
// Запуск игры при нажатии кнопки
myDFPlayer.play(8);
delay(700);
startGame();
}
} else {
myDFPlayer.play(4);
Serial.println("Not enough money!");
}
}
}
} else if (i == 1) {
myDFPlayer.play(3);
// MAX BET
totalBet = maxPlayBet; // Устанавливаем максимальную ставку
displayBetNowToMatrix(); // Отображаем ставку
} else if (i == 2) {
myDFPlayer.play(3);
// BET ONE
if (totalBet == maxPlayBet) {
totalBet = minPlayBet;
displayBetNowToMatrix();
} else {
totalBet += minPlayBet; // Устанавливаем ставку
displayBetNowToMatrix(); // Отображаем ставку
}
} else if (i == 3) {
if (clickOneCollect == true) {
lcd.clear();
lcd.print("Wait...");
for (int i = 0; i < 3; ++i) {
digitalWrite(redPin[i], LOW);
digitalWrite(bluePin[i], LOW);
digitalWrite(greenPin[i], LOW);
}
delay(200);
digitalWrite(greenPin[0], HIGH);
digitalWrite(greenPin[1], HIGH);
digitalWrite(greenPin[2], HIGH);
delay(200);
// send command to printer TTL
handleLEDs();
} else {
clickOneCollect = true;
Serial.println("Collect money");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Collect?");
lcd.setCursor(0, 1);
lcd.print("Click \"collect\"");
}
Serial.println("hello");
} else {
Serial.println("ERROR BUTTON IS NOT DEFIND");
}
}
delay(50); // Небольшая задержка для устранения дребезга контактов
}
// Обновляем последнее известное состояние кнопки
lastButtonStates[i] = buttonStates[i];
}
// Постоянно генерируем числа
randomCombination = grnMachine();
// Выводим текущую сумму каждые 200 миллисекунд
/*
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate >= 200) {
Serial.print("Текущая сумма: ");
Serial.print(totalAmount);
Serial.println(" рублей");
lastUpdate = millis();
}*/
}
String convertNumberToRGBString(int number) {
String result = "";
while (number > 0) {
int digit = number % 10;
char letter = getLetterForDigit(digit);
result = letter + result; // Добавление символа в начало строки
number /= 10;
}
return result;
}
char getLetterForDigit(int digit) {
switch (digit) {
case 1:
return 'R';
case 2:
return 'G';
case 3:
return 'B';
default:
return '?'; // На случай неверного ввода
}
}
void setColor(int color, int index) {
digitalWrite(redPin[index], LOW);
digitalWrite(greenPin[index], LOW);
digitalWrite(bluePin[index], LOW);
switch (color) {
case 1:
digitalWrite(redPin[index], HIGH);
break;
case 2:
digitalWrite(greenPin[index], HIGH);
break;
case 3:
digitalWrite(bluePin[index], HIGH);
break;
}
}
void startGame() {
// Сохраняем текущий результат
lastResult = randomCombination;
minLoseBet(); // Забираем ставку
displayBetNowToMatrix(); // Отображаем игроку
// Сохраняем текущее время для отслеживания длительности вращения
startTime = millis();
while (millis() - startTime <= spinDuration) {
// Рандомное мигание светодиодов во время вращения
randomBlinkLEDs();
delay(20); // Задержка между циклами мигания
}
// Выводим результат пользователю
int digit1 = lastResult / 100; // Первая цифра
int digit2 = (lastResult / 10) % 10; // Вторая цифра
int digit3 = lastResult % 10; // Третья цифра
setColor(digit1, 0); // Управляем первым набором светодиодов
setColor(digit2, 1); // Управляем вторым набором светодиодов
setColor(digit3, 2); // Управляем третьим набором светодиодов
// Сравниваем выпавший пользователю результат с комбинацией
String combinationCurrent = convertNumberToRGBString(lastResult);
bool winOrLose = true;
if (totalBet == minPlayBet) {
if (combinationCurrent == "BBB") {
totalAmount += firstCombM;
} else if (combinationCurrent == "RRR") {
totalAmount += secondCombM;
} else if (combinationCurrent == "GGG") {
totalAmount += thirdCombM;
} else if (combinationCurrent == "RRG") {
totalAmount += fourthCombM;
} else if (combinationCurrent == "RRB") {
totalAmount += fourthCombM;
} else if (combinationCurrent == "GRR") {
totalAmount += fourthCombM;
} else if (combinationCurrent == "BRR") {
totalAmount += fourthCombM;
} else {
winOrLose = false;
}
} else if (totalBet == betweenPlayBet) {
if (combinationCurrent == "RRR") {
totalAmount += firstCombB;
} else if (combinationCurrent == "RRG") {
totalAmount += secondCombB;
} else if (combinationCurrent == "RRB") {
totalAmount += secondCombB;
} else if (combinationCurrent == "GRR") {
totalAmount += secondCombB;
} else if (combinationCurrent == "BRR") {
totalAmount += secondCombB;
} else {
winOrLose = false;
}
} else if (totalBet == maxPlayBet) {
if (combinationCurrent == "BBB") {
totalAmount += firstCombS;
} else if (combinationCurrent == "RRG") {
totalAmount += secondCombS;
} else if (combinationCurrent == "RRB") {
totalAmount += secondCombS;
} else if (combinationCurrent == "GRR") {
totalAmount += secondCombS;
} else if (combinationCurrent == "BRR") {
totalAmount += secondCombS;
} else {
winOrLose = false;
}
} else {
Serial.println("Error in totalBet GAME END");
}
if (winOrLose == true) {
myDFPlayer.play(6);
handleLEDs();
}
displayBetNowToMatrix();
}
void handleLEDs() {
// Проверяем состояние светодиодов
checkLEDStates();
// Начинаем мигание
startBlinking();
}
void checkLEDStates() {
// Читаем состояние всех светодиодов
for (int i = 0; i < numRedLEDs; ++i) {
ledState[i] = digitalRead(redPin[i]) == HIGH ? true : false;
}
for (int i = 0; i < numBlueLEDs; ++i) {
ledStateBlue[i] = digitalRead(bluePin[i]) == HIGH ? true : false;
}
for (int i = 0; i < numGreenLEDs; ++i) {
ledStateGreen[i] = digitalRead(greenPin[i]) == HIGH ? true : false;
}
}
void startBlinking() {
// Запускаем мигание
startBlinkTime = millis();
while (millis() - startBlinkTime < blinkDuration) {
// Меняем состояние всех светодиодов
for (int i = 0; i < numRedLEDs; ++i) {
if (ledState[i]) {
digitalWrite(redPin[i], HIGH);
} else {
digitalWrite(redPin[i], LOW);
}
}
for (int i = 0; i < numBlueLEDs; ++i) {
if (ledStateBlue[i]) {
digitalWrite(bluePin[i], HIGH);
} else {
digitalWrite(bluePin[i], LOW);
}
}
for (int i = 0; i < numGreenLEDs; ++i) {
if (ledStateGreen[i]) {
digitalWrite(greenPin[i], HIGH);
} else {
digitalWrite(greenPin[i], LOW);
}
}
delay(blinkInterval / 2);
for (int i = 0; i < numRedLEDs; ++i) {
digitalWrite(redPin[i], LOW);
}
for (int i = 0; i < numBlueLEDs; ++i) {
digitalWrite(bluePin[i], LOW);
}
for (int i = 0; i < numGreenLEDs; ++i) {
digitalWrite(greenPin[i], LOW);
}
delay(blinkInterval / 2);
}
// После завершения мигания возвращаемся в исходное состояние
for (int i = 0; i < numRedLEDs; ++i) {
digitalWrite(redPin[i], ledState[i] ? HIGH : LOW);
}
for (int i = 0; i < numBlueLEDs; ++i) {
digitalWrite(bluePin[i], ledStateBlue[i] ? HIGH : LOW);
}
for (int i = 0; i < numGreenLEDs; ++i) {
digitalWrite(greenPin[i], ledStateGreen[i] ? HIGH : LOW);
}
}
void randomBlinkLEDs() {
// Случайное включение одного светодиода
int ledIndex = random(0, 3);
int color = random(0, 3);
switch (color) {
case 0:
digitalWrite(redPin[ledIndex], HIGH);
break;
case 1:
digitalWrite(bluePin[ledIndex], HIGH);
break;
case 2:
digitalWrite(greenPin[ledIndex], HIGH);
break;
}
delay(random(30, 70)); // Случайная задержка перед выключением
// Выключение того же светодиода
switch (color) {
case 0:
digitalWrite(redPin[ledIndex], LOW);
break;
case 1:
digitalWrite(bluePin[ledIndex], LOW);
break;
case 2:
digitalWrite(greenPin[ledIndex], LOW);
break;
}
}
int grnMachine() {
int num1, num2, num3;
// Генерация трех случайных чисел от 1 до 3
num1 = random(1, 4); // Генерируем первое число
num2 = random(1, 4); // Генерируем второе число
num3 = random(1, 4); // Генерируем третье число
// Проверка вероятности того, что все три числа одинаковы
if (random(100) < PROBABILITY_SAME_ALL) {
num2 = num1;
num3 = num1;
}
// Проверка вероятности того, что две единицы будут рядом
if ((num1 == 1 && num2 == 1) || (num2 == 1 && num3 == 1)) {
if (random(100) >= PROBABILITY_11_NEARBY) {
if (num1 == 1 && num2 == 1) {
num2 = random(2, 4);
} else {
num3 = random(2, 4);
}
}
}
String resultch = String(num1) + String(num2) + String(num3);
int result = resultch.toInt();
return result;
}