Алгоритм выбора с условием

Есть пункты меню. Необходимо по нажатию кнопки выделять эти пункты по очереди. Но есть условия, когда некоторые пункты выбирать нельзя, их нужно пропустить. Вот пример из трех пунктов:
bool a, b, c; //если false значит выбирать этот пункт нельзя.
byte ind; //индекс выбранного пункта. 0 - ничего не выбрано.
Например в какой то момент пункты в таком состоянии:
a = false; b = true; c = false;
То значения ind должны быть циклично по нажатию кнопки такие: 2 0 2 0 2…
При a = true; b = true; c = true;
ind будут 0 1 2 3 0 1 2 3 0…
if (lnd < 3) lnd++; else lnd =0;
Это если не учитывать возможность выбора, а как сделать с учётом? Ну и вдруг это нужно будет сделать не с 3 а с 5 пунктами и допустим выбрать можно первый и пятый… (значения lnd 015015015…) Это я об универсальности алгоритма, а не тупой перебор всех вариантов lfами… Т.е. вопрос в том как рассчитывать этот самый ind
Пункт меню с индексом ind при отрисовки будет рисоваться выделенным. Но вопрос не в рисовании, а как грамотно перебирать значения lnd циклично

Покажите, пожалуйста, как Вы пытались решить эту задачу.

Только не вот это вот

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

Должны же Вы были сделать какую-то попытку самостоятельно, прежде, чем писать сюда.

Согласно лучшим традициям индусских программистов именно тупой перебор всех вариантов является наиболее оптимальным решением.

Я думал есть какие-то “стандартные” решения данного вопроса. Вопрос набирал с телефона, и показать как я пробовал сейчас не смогу, но обязательно, как доберусь до компьютера(но как скоро это будет, не могу к сожалению сказать) то покажу как я сделал этот алгоритм… Просто думаю, что есть грамотное решение данного алгоритма…
И да, я пока сделал только для определённого кол-ва пунктов меню, конкретно для 3, но расширить до любого кол-ва можно моё решение, но оно требует некоей модернизации кода…

if (ind ==0)
if (a) ind = 1; else if (b) ind = 2; else if (c) ind = 3;
if (ind == 1) if (b) ind=2;else if (c) ind = 3; else ind = 0;
if (ind == 2) if (c) ind=3; else ind =0;
if (ind == 3) ind =0;
Так что ли? Но это ужасно)

Войдите на старый форум. Наберите в строке поиска слово меню. Выбирайте разные варианты.

Да это в общем то не совсем меню (это я его так обозвал) Думал вообще к меню не относится… Это вроде как частный случай с одной стороны, но точно не я это придумал - с другой. Даже не знаю как это искать, а просматривать целиком решения по “меню” то ещё занятие… В чужом коде ещё и разобраться нужно… (

Данным вопросом занимался позавчера. Пробовал разные варианты, в основном ничего не получалось, на каком остановился сейчас не вспомню, впрочем рабочих было наверное всего два: (скажу честно, набираю с телефона без возможности проверить, но надеюсь ошибок не будет)

bool a, b, c;
byte ind;

void setup() {
 Serial.begin(115200);
//тут меняем у пунктов возможность выбора
 a=c=true; b=false;
 ind=0;
}

byte getNextIndex(byte currInd) {
 if (currInd == 3) return 0;
 if (currInd ==0) if (a) return 1;
else if (b) return 2; else if (c) return 3; else return 0;
 if (currInd == 1) if (b) return 2; else if (c) return 3; else return 0;
 if (currInd == 2) if (c) return 3; else return 0;
}

void loop() {
 ind = getNextIndex(ind) ;
 Serial.println(ind);
 delay(500);
} 

Прошу прощение, не знаю как с телефона правильно оформить код :frowning:
О, бл… получилось))

Чтобы наметить изящное решение, Вам нужно познакомиться с таким понятием как массивы.

2 лайка

Завести массив статуса пунктов меню. и проверять в условии, активен пункт или нет . Там же(в массиве статуса) производить необходимые изменения по ходу программы

byte menuItemStat[] = {1, 1, 1, 1, 0};

 if(menuItemStat[0] )
//если пункт 0 меню активен - выполнить

:slight_smile: знаком
Этот массив придётся переписывать каждый раз во время нажатия кнопки. Так как пункты могут сменить состояние возможности его выбора в любой момент. Вряд-ли с массивом будет проще… Чем я уже сделал.
У меня была мысль, что можно как-то использовать булевские значения при прибавление к ind.
Доберусь до компа, посмотрю как я ещё пробовал делать, покажу как сделаю(л)

В итоге то получается тот же самый код что и выше я нарисовал в 8
Хотя…может и можно попробовать заморочится с массивом… Надо будет попробовать… Там как бы не в хранении состояний пунктов вопрос, а их (состояние возможности выбора в текущий момент времени) учёт при изменении ind

В моем примере в 8 заменить луп на этот
void loop() {
a=random(2);
b=random(2);
c=random(2);
ind = getNextIndex(ind) ;
Serial.println(ind);
delay(500);
}

Это конечно слишком частая смена состояний, но… Примерно далеко но как то так)

И да, меня интересует только функция getNextIndex, остальной код только для её тестирования)

Хотя если рандом не из 2 сделать а попробовать из 10 (например или больше) 0 будет реже выпадать, может получится поудобнее тестировать (это я для себя :)))

Уверен?

const uint8_t maxItem = 5;
uint8_t menuItemStat[] = {1, 0, 1, 1, 0};
uint8_t currentIndex = 0;

uint8_t getNextIndex(uint8_t currInd);

void setup() {
  Serial.begin(9600);
  for (uint8_t i = 0; i < 10; i++) {
    Serial.println(currentIndex);
    currentIndex = getNextIndex(currentIndex + 1);
  }
}

void loop() {

}

uint8_t getNextIndex(uint8_t currInd) {

  if ( menuItemStat[currInd] ) {     //если пункт меню активен
    return currInd;
  }
  currInd++;
  if ( currInd >= maxItem ) {
    currInd = 0;
  }
  return getNextIndex(currInd);
}

Вывод:

0
2
3
0
2
3
0
2
3
0

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

Кстати, гуру программирования (особенно по рекурсиям).
А почему при таком массиве:

uint8_t menuItemStat[] = {0, 0, 1, 0, 1};

Полная ерунда в выводе? :smiley:

2
4
5
6
2
4
5
6

Откуда 5 и 6 берется? ))

// структура, описывающая пункт меню
struct MenuItem 
{
  bool active;   // активен ли пункт меню
  char *name;  // строка пункта меню
};

// инициализация массива пунктов меню
MenuItem items[] = {
    MenuItem{true,
             "First item"},
    MenuItem{true,
             "Second item"},
    MenuItem{false,
             "Third item"},
    MenuItem{true,
             "LastItem"}};

...............................

// работа с пунктами меню
if (items[0].active)
{
  /* Если пункт меню активен */
}

.

Ещё можно числом обозначать набор “разрешимостей” - 0b10011001 (034703470…)

:slight_smile:
А их вставить в массив или менять значение формульно.

Фу, как некрасиво!

Ну, Вы же говорите, “бл@дь”, а говорите “путана”, не “пидар@с” - а “гей”. Ну и здесь говорите: “Метод британского музея” - вумно, загадочно, по-европейски!

1 лайк

@ЕвгенийП , объясните что я не так сделал в #15, что в #16 - 5 и 6 «вылазят»?