Выбор правильного варианта из предложенных ардуино

Dem
Offline
Зарегистрирован: 02.09.2018
Добрый вечер!
Прощу помощи у опытных ардуищиков! 
Имеется код, но не могу докумекать как заставить его работать как нужно. 
 
Идея вот какая: на LCD (1602 подключен по I2C к ардуино нано) выводится вопрос: "Первый ответ, выберите A, B,C,D". Затем с клавы (клавиатура мембранная, 4х4) вводится  нужная буковка и, если ответ правильный, вылазит что-то вроде "ПРАВИЛЬНО" и после этого выводится "Второй ответ, выберите A, B, C, D" ну и дальше четвертый, пятый и т.д. Если неправильный, сгорает одна жизнь (заранее задается количество). Если сгорает последняя жизнь, то на дисплее что-то вроде: ГЕЙМ ОВЕР и дисплей гаснет, на кнопки не реагирует. 
 

ПРОБЛЕМА: не могу додуматься, как сравнивать букву (нажатую кнопку на клаве), полученную от пользователя, с уже зашитым (правильным) вариантом для каждого из вопросов. Т.е. как сделать так, чтоб после получения правильного ответа от пользователя, програма сравнивала его с извесным. Если полученный ответ правильный, на экран выводить (ПРАВИЛЬНО) и показывать следующий вопрос. Если неправильный - чтоб величина, отвечающая за "жизни" стала меньше на 1. Если жизни закончатся - гейм овер. Если все ответы правильные и жизни не закончились - победа.

 
На сколько мне хватило знаний, написал, дальше прошу Вашей помощи... Матчасть читал, но додуматься как довести идею до финиша - немогу...

 

С програмированием дело имел только в школе, сейчас решил занятся так как преподаю деткам английский на дому. Решил сделать "умного робота", в какой заранее забиваю правильные ответы, а детки с ним взаимодействуют. Типо решил задание, выбрал вариант, а робот проверил. Сами понимаете, заитересовывать и учить молодое поколение нужно любыми средствами. По образованию - инженер строитель, по призванию учитель английсого языка. Ардуинка - хобби. Прошу прощения за много лишнего текста, вот код 
 
#include <Keypad.h>
#include <Servo.h>
#include <LCD_1602_RUS.h>

Servo servo; // в конце, если все ответы правильные, севра открывает лючок где лежит конфетка. Но до этого еще далеко

char question1 = 'A'; // тут вводятся правильные ответы.
char question2 = 'B';
char question3 = 'B';
char question4 = 'D';
char question5 = 'C';

LCD_1602_RUS lcd(0x27, 16, 2);

int ilosc; // number of clicks

const byte ROWS = 4; // 4 строки
const byte COLS = 4; // 4 столбца
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {12, 11, 10, 9}; // тут пишем диджитал пины к которым клава коннектится к ардуинке.
byte colPins[COLS] = {8, 7, 6, 5};   //  Просто тупо слева направо первые 4 это ROWS последние 4 COLS.

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
  Serial.begin(9600);

  servo.attach(2);
  lcd.begin();
  lcd.setCursor(0, 0);
  lcd.print("ПЕРВЫЙ ОТВЕТ:");
  lcd.setCursor(0, 1);
  lcd.print("Выберите A,B,C,D");
}
void loop() {

  lcd.setCursor(0, 0);
  lcd.print("ПЕРВЫЙ ОТВЕТ:");
  lcd.setCursor(0, 1);
  lcd.print("Выберите A,B,C,D");

  char key = keypad.getKey();
  if (key == 'A')
  {
    lcd.setCursor(9, 1);
    lcd.cursor();                 // показываем курсор
    lcd.blink();                  // заставляем его мигать
    delay(3000);
    lcd.noBlink();
  }
  else if (key == 'B')
  {
    lcd.setCursor(11, 1);
    lcd.cursor();                 // показываем курсор
    lcd.blink();                  // заставляем его мигать
    delay(3000);
    lcd.noBlink();
  }
  else if (key == 'C')
  {
    lcd.setCursor(13, 1);
    lcd.cursor();                 // показываем курсор
    lcd.blink();                  // заставляем его мигать
    delay(3000);
    lcd.noBlink();
  }
  else if (key == 'D')
  {
    lcd.setCursor(15, 1);
    lcd.cursor();                 // показываем курсор
    lcd.blink();                  // заставляем его мигать
    delay(3000);
    lcd.noBlink();

    lcd.setCursor(0, 0);
    lcd.print("ВТОРОЙ ОТВЕТ:");
    lcd.setCursor(0, 1);
    lcd.print("Выберите A,B,C,D");
    delay(3000);
    if (key == 'A')
    {
      lcd.setCursor(9, 1);
      lcd.cursor();                 // показываем курсор
      lcd.blink();                  // заставляем его мигать
      delay(3000);
      lcd.noBlink();
    }
    else if (key == 'B')
    {
      lcd.setCursor(11, 1);
      lcd.cursor();                 // показываем курсор
      lcd.blink();                  // заставляем его мигать
      delay(3000);
      lcd.noBlink();
    }
    else if (key == 'C')
    {
      lcd.setCursor(13, 1);
      lcd.cursor();                 // показываем курсор
      lcd.blink();                  // заставляем его мигать
      delay(3000);
      lcd.noBlink();
    }
    else if (key == 'D')
    {
      lcd.setCursor(15, 1);
      lcd.cursor();                 // показываем курсор
      lcd.blink();                  // заставляем его мигать
      delay(3000);
      lcd.noBlink();
    }
    else if (key == '1', '2', '3', '4', '5', '6', '7', '8', '9')
    {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Цифры не трогать");
      lcd.noCursor();
      delay(1000);
      lcd.noBlink();
    }
  }
}

 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ну, во-первых, все подобные задачи решабтся алгоритмом, который называется "конечный автомат" (вот уже и ключевое слово для поиска).

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

Dem
Offline
Зарегистрирован: 02.09.2018

Вопросы будут на листочке. Ребеночку лишь нужно будет тыцнуть на кнопку ответа, какой он или она считает правильным.

Ключевое слово, это уже что-то, спасибо!

Спасибо за идею с массивом, но, честно скажу не совсем понятно... Будьте добры, объясните, пожалуйста, на примере... (можно даже в моем коде :-))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

На листочке - это неправильно. Как Вы планируете добиться синхронизации между листочками и Ардуино? Как Ардуино сможет узнать, какой листочек лежит перед ребенком? Это будет постоянная путаница.

Собственно, пока у Вас не будет четкого понимания на уровне постановки задачи, надеяться что что-то получится с реализацией - чрезмерно оптимистично.

Но если у Вас есть набор вопросов, то, очевидно, что каждый из них можно представить в виде некоторого шаблона, т.е. набора полей. В простейшем случае поля два: текст вопроса и номер ответа. Логично реализовать вопрос в виде структуры или класса. А т.к. вопросов у Вас несколько, то организовать их в массив. Индекс в массиве - номер вопроса. После отработки очередного вопроса индекс увеличивается на 1, т.е. переходим к следующему.

Dem
Offline
Зарегистрирован: 02.09.2018

Сформулировать все идеи - вот это сложно. Хочется начать с чего-то простого. Сделать своебразный скелет. Систему вопрос-ответ. А потом наращивать на эту систему дополнения. Четкое понимание на уровне постановки задачи есть. Но если я выброшу сюда все куски кода, какие мне удалось притянуть с разных проэктов, то большинство просто поленятся прочитать мои сообщения. Общая идея такова: у каждого ребенка есть имя и фамилия. К этим данным привязывается RFID ключ, какой дается каждому ребенку. Каждый ребенок получает своеобразный пульт (над кодом которого я и хочу, чтоб вы мне помогли). Доступ к пульту осуществляется рутем считывания личной RFID метки. Все пульты коннектятся с базой (ардуино мега, или уно, смотря что осилю) и передает статистику ответов каждого ребенка. А база передает инфу на мой сайт, где родители, в режиме реального времени следят за успехами чада. Эдакий электронный дневник. Хорошая система, правда? При этом база  подбирает задания для каждого ребенка по уровню сложности, какие задаются заранее на основе статистики успеваемости ребёнка, бережно собранной и переданной пультом, системой, с какой я прошу Вас мне помочь! На выходе я от базы получаю лишь номер папки, с какой нужно взять задание, и номер этого самого задания. Как Вам, есть у меня четкое понимание на уровне постановки задачи? Поможете осуществить хоть малую часть? А дальше я как-то сам?

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

База подбирает? Это что-то типа искуственного интеллекта что ли?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Dem пишет:

Но если я выброшу сюда все куски кода, какие мне удалось притянуть с разных проэктов, то большинство просто поленятся прочитать мои сообщения.

Вы всерьез думаете, что если взять "Анну Каренину" и "Капитанскую дочку", надергать оттуда цитат и слепить в единое целое, - получится нетленка?

С точки зрения авторского права тексты программ приравниваются к литературному произведению. И писать их надо так же: план, наброски, потом прорисовка деталей и т.д. Абзацы или фразы из существующих произведений проблему не решат, а только заведут в тупик.

Цитата:

Как Вам, есть у меня четкое понимание на уровне постановки задачи?

IMHO нет. Есть плохо структурированный набор хотелок.

Начните с чего-то попроще. Ну, например, с программы вопрос-ответ. Т.е программа задает несколько вопросов, получает ответы, а в конце выдает статистику правильных.

В принципе, если у Вас нулевой уровень, то и это сложновато. Найдите либо книжку по Ардуино, либо видеоуроки и пройдите по примерам.

Dem
Offline
Зарегистрирован: 02.09.2018

Выше в скобочках я словом БАЗА условно назвал ардуино уно или мега, (пока незнаю), с какими ардуино нано будет обмениватися информацией про ученика.

Dem
Offline
Зарегистрирован: 02.09.2018

А здесь я не согласен. Есть же общепринятые шаблоны, такие как подключение мембранной клавиатуры или подключение дисплея. Здесь никто на авторское право не посягает.

Ну, простите, может где-то неточно написал, но идея-то есть.

Не поверите, с системой вопрос-ответ я и прошу мне помочь. Она должна быть построена на if и else, я так понимаю? Неужели нет какого-то шаблона, дабы не изобретать велосипед?

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

Долгий путь у вас от скетча в посте #1 до системы, которую расписали. Ищите сразу компаньона-подельника, иначе полгода всяких проб и ошибок обеспечено.

Шаблоны есть - называются "Пример к библиотеке N", но проблема в том, что каждый "скетчестроитель" видит алгоритм не так, как остальные, поэтому найти шаблон, который его бы удовлетворил сразу - великое везение. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, не согласен, значит не согласен - все мы свободные люди и можем иметь своём нение :)

Dem
Offline
Зарегистрирован: 02.09.2018

Спасибо за подсказки, господа. Буду разбираться и искать компаньйона :-)

5N62V
Offline
Зарегистрирован: 25.02.2016

Dem пишет:

ПРОБЛЕМА: не могу додуматься, как сравнивать букву (нажатую кнопку на клаве), полученную от пользователя, с уже зашитым (правильным) вариантом для каждого из вопросов. Т.е. как сделать так, чтоб после получения правильного ответа от пользователя, програма сравнивала его с извесным. Если полученный ответ правильный, на экран выводить (ПРАВИЛЬНО) и показывать следующий вопрос. Если неправильный - чтоб величина, отвечающая за "жизни" стала меньше на 1. Если жизни закончатся - гейм овер. Если все ответы правильные и жизни не закончились - победа.
 
Ну я бы делал скорее всего так:
1) завел массив строк, каждый элемент которого содержит вопрос
2) завел второй массив с  таким же количеством элементов, где содержатся правильные ответы. Ячейка с индексом n содержит привальный ответ  к вопросу n из массива вопросов.
2а) завел еще один массив ответов, число ячеек = предполагаемому числу задаваемых за сет вопросов
3) Рандомно выбираем вопрос из массива, выводим на дисплей, например элемент z  из массива вопросов
4) дите отвечает, нажимая клавишу, при этом переменной answer присваивается номер ответа
5) сравниваем значение переменной answer и элемента z из массива ответов
6) если answer и элемент z из массива ответов совпадают, то в массив правильных ответов в текущую позицию записывам, скажем, 1. Если не совпадают, то записываем 0, и уменьшаем на 1 переменную "количество жизней".
7) анализируем, выводим результат, ну или гейм овер, в зависимости от ситуэйшн.
 
Когда Вы себе распишите таким образом весь алгоритм, а лучше подробнее, тогда написать программу будет просто.  PS.Без претензий на истину ;)
 
Dem пишет:
Идея вот какая: на LCD (1602 подключен по I2C к ардуино нано) выводится вопрос
Тут как бы шибко длинных вопросов у Вас не получится, да еще и с индикацией вариантов ответов - аще без перспектив.
mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

А я по простому отвечу:

У Вас есть матрица провильных ответов. Например char Otvet[50]={"A","B","C"...}

Далее Вы перебираете вопросы в цикле for(i=1;i<50;i++)

и сравниваете Otvet[i] с введенной буквой.

Вот и все :)

Dem
Offline
Зарегистрирован: 02.09.2018

Идею понял, вот как только это написать - как раз хочу разобраться. 

По поводу дисплея - на 1602 только пытаюсь прощупать ардуину. Потом закуплю 12864. Так будет интереснее...)

Dem
Offline
Зарегистрирован: 02.09.2018

Про матрицу мне понравилось. Руки дойдут - проверю на практике, спасибо!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
enum answer_t {ansA, ansB, ansC, ansD}; /*вариант ответов A,B,C,D*/
struct note_t {
  char *question;/*вопрос*/
  char *answerA;/*ответ A*/
  char *answerB;/*ответ B*/
  char *answerC;/*ответ C*/
  char *answerD;/*ответ D*/
  answer_t correct_answer;/*правильный ответ */
};
const char question1 PROGMEM = "question1";
const char answer1A PROGMEM = "answer1A";
const char answer1B PROGMEM = "answer1B";
const char answer1C PROGMEM = "answer1C";
const char answer1D PROGMEM = "answer1D";

const char question2 PROGMEM = "question2";
const char answer2A PROGMEM = "answer2A";
const char answer2B PROGMEM = "answer2B";
const char answer2C PROGMEM = "answer2C";
const char answer2D PROGMEM = "answer2D";

const char question3 PROGMEM = "question3";
const char answer3A PROGMEM = "answer3A";
const char answer3B PROGMEM = "answer3B";
const char answer3C PROGMEM = "answer3C";
const char answer3D PROGMEM = "answer4D";

const note_t notes[] PROGMEM = {
  {question1, answer1A, answer1B, answer1C, answer1D, ansA}
  , {question2, answer2A, answer2B, answer2C, answer2D, ansD}
  , {question3, answer3A, answer3B, answer3C, answer3D, ansB}
};

void setup() {


}

void loop() {
  // put your main code here, to run repeatedly:

}

 

Dem
Offline
Зарегистрирован: 02.09.2018

Спасибо!

Я б до такого не додумался...)

Dem
Offline
Зарегистрирован: 02.09.2018

Никаие библитеки не нужны дополнительно? А то ругается...

Arduino: 1.8.5 (Mac OS X), Плата:"Arduino Nano, ATmega328P"
 
4: note: 'const note_t notes [3]' previously defined here
 const note_t notes[] PROGMEM = {
              ^
exit status 1
conflicting declaration 'const char question1'
 
sadman41
Offline
Зарегистрирован: 19.10.2016

Ругается - потому что квон ошибки оставляет в своем коде. Учит таким образом, так скыть, нубов.

5N62V
Offline
Зарегистрирован: 25.02.2016

Dem пишет:

Про матрицу мне понравилось. Руки дойдут - проверю на практике, спасибо!

ну дык до матрицы еще дорасти надо. С массивами -то на порядок легче !

Dem
Offline
Зарегистрирован: 02.09.2018

Ааа, образовательный момент, тоже правильно!

5N62V, согласен, да, матрица - это высший пилотаж. Но согласитесь - красиво!

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

sadman41 пишет:

Ругается - потому что квон ошибки оставляет в своем коде. 

Не ругай Пуха, он не спицально. 

5N62V
Offline
Зарегистрирован: 25.02.2016

Dem пишет:

5N62V, согласен, да, матрица - это высший пилотаж. Но согласитесь - красиво!

полностью с Вами солидарен по этому вопросу! Кто постиг матрицы - на массивы смотрит снисходительно. :)