Делаю небольшую викторину. Есть две кнопки, по нажатию которых воспроизводятся звуковые файлы в заданной последовательности. Сама таблица последовательностей такая: Т.е. по нажатии кнопки А воспроизводится файл №1, если потом снова нажата кнопка А, то воспроизводится файл №2, но если нажата кнопка Б, то прыгаем сразу на файл №4. Пока задумка такая: массив из 3хN ячеек, где записаны нужные индексы. Отслеживаем текущее значение и по нажатии кнопки переходим по индексу А или Б. Но это получается очень громоздко (много if или switch) и сложно в отладке. Может есть более оптимальный способ? P.S. Если очень надо в целях автоматизации, можно в каждом блоке вопросов сделать одинаковое количество ячеек (просто некоторые будут пустые, без вопросов).
Если я правильно понял, то: 1. Вход (первое нажатие на кнопку А) - играем мелодию N; 2. Выход №1 (второе нажатие на кнопку А) - играем мелодию M; 3. Выход номер 2 (нажатие на кнопку Б) - играем мелодию Z. Судя по табличке - бинарное дерево в чистом виде. Можно построить в памяти сразу, и тогда не надо будет никакого множества switch и if - будут просто работать переходы. Если память не жмёт - можно структурками изобразить, что-то типа этого: Код (C++): struct leaf; typedef struct { leaf* left; // ссылка на левый узел leaf* right; // ссылка на правый узел byte melody; // номер мелодии } leaf; И простроить дерево при старте, хоть из каких исходных данных. Если такой подход не устроит - будем думать
Эм, а дерево как хранить, в массиве? Разбираюсь, вроде все понятно. Допустим, текущий файл #5, как передать в структуру что нажата кнопка Б?
Смотрите: вы отстраиваете дерево при старте. Если нажата кнопка А - то путь в дереве - по ветке left. Если нажата кнопка B - то путь в дереве - по ветке right. Допустим, у нас уже есть сформированное дерево, и мы стоим у ствола: Код (C++): leaf* currentLeaf= getRoot(); playMelody(currentLeaf->melody); if(isAButtonPressed()) { currentLeaf = currentLeaf->left; } else currentLeaf = currentLeaf->right; playMelody(currentLeaf->melody); Дерево можно отстраивать при старте, как я уже писал. Это не совсем тривиально порой, но - вполне решаемо. На выходе получите любую нужную вам конфигурацию, в том числе такие случаи, как закольцованность и прочие ништяки. Про инициализацию дерева - вопрос отдельный, с наскока не решается. Я же говорю - если этот вариант устроит, будем продолжать. Если нет - всегда можно найти вариант попроще. То, о чём ведётся речь, не что иное, как связанный список. Вернее, одна из его разновидностей.
Нет, правда, чем плоха идея с массивом 3х20? Задача то простая совсем. зачем решать ее сложно? Чтобы легче запутаться и труднее потом исправлять если что? Поясните для начинающего смысл пложения сущностей без нужды.
Про инициализацию дерева при старте: во-первых, надо знать кол-во шагов всего, и инициализировать все структуры: Код (C++): #define COUNT_STEPS 20 leaf* tree[COUNT_STEPS]; void setup() { for(byte i=0;i<COUNT_STEPS;i++) { tree[i] = new leaf; } } Далее - надо заполнить связи структур. Допустим, у вас есть массив с настройками вида Код (C++): typedef struct { byte enter_melody; // мелодия, играющаяся на входе byte a_pressed; // мелодия, играющаяся по кнопке A byte b_pressed; // мелодия, играющаяся по кнопке Б } byte_code; byte_code codes[COUNT_STEPS] = { {1,2,4}, {3,1,5}, // и т.п. }; Тогда простройка дерева будет выглядеть так: Код (C++): for(byte i=0;i<COUNT_STEPS;i++) { byte_code bc = codes[i]; leaf* l = tree[i]; l->left = tree[bc.a_pressed]; l->right = tree[bc.b_pressed]; l->melody = bc.enter_melody; } Писал навскидку, надеюсь, подход понятен. Дальнейшая обработка - мизерна и без чудовищных switch и if
Универсальность. Структурированность. Документированность. Лёгкость расширения и сопровождения. Системность подхода. Достаточно? Не навязываю, просто я так привык - если можно задачу обобщить без больших телодвижений - то это и делаю. Я уже почти весь скетч тут в ответах написал, собственно - где там сложность? А вот если делать в лоб - сложность обязательно будет, если надо будет перестроить граф, и придётся копаться в кишочках, продираясь через череду if и прочих условий. Зачем, если можно сначала полчаса потерять, а потом за пять минут долететь? (с) "Крылья, ноги и хвосты".
На мой взгляд массив мелодий 3х20, в виде копии таблицы из первого сообщения, проще, структурированней, легче для понимания, исправлений и дополнений, чем "бинарное дерево". Плюс функция обработки нажатий на пару тройку строк, а не чудовищных if и swith. Могу ошибаться, конечно, но лучше полчаса не терять, а сразу за пять минут долететь.
1. Ждем нажатия кнопки А, играем melody(0)(i) 2. Ждем нажатия кнопки А или Б, играем melody(1)(i) или melody(2)(i) 3. Ждем отпускания нажатой кнопки. 4. i++, повторяем п.1 - 3 20 раз. Проще некуда, и как ни крути, массив мелодий все равно создавать, ибо они не вычисляемы, а директивны. Или я не так понял задание? Просто я недавно делал школьный звонок по похожему принципу: массив из режимов и звонков, работает отлично и программа очень наглядна, исправить/добавить/удалить что то расписания может даже не автор.
С использованием массивов задача проще решается. Вот только хватит одного массива и индекса текущей мелодии: Код (C++): // индекс текущей мелодии // 0 -- начальное состояние: ни одна кнопка ни разу ни нажата volatile unsigned char currentMelody = 0; // массив индексов мелодий (заполняется в соответствии с таблицей) // первая размерность -- количество вопросов // вторая -- количество кнопок (кнопок может быть любое количество) unsigned char melodies[18][2] = { {1, 1}, // при первом нажатии любой кнопки играем первую мелодию {2, 4}, {3, 4}, {3, 4}, ..... }; Далее: Код (C++): // buttonIndex = 0, когда нажата кнопка А // buttonIndex = 1, когда нажата кнопка Б // и т.д. // возвращает номер мелодии, которую нужно исполнить unsigned char onButtonPressed(unsigned char buttonIndex) { currentMelody = melodies[currentMelody][buttonIndex]; return currentMelody; }
Ребят, я не спорю, что можно проще и в лоб. Я так привык, поймите - когда оказывается, что задача включает не только это, но и ещё чего-то. И тогда - всё: ни убавить, ни прибавить, и начинаются пляски разного рода. Поэтому, когда я не полностью знаю, в чём заключается задача - предпочитаю выдавать более общее, расширяемое в дальнейшем решение. Без претензий.
Спору нет, ваш способ интересный и даже поучительный. Можно на одном этом примере разбираться как работать со структурами. Но задача не настолько проста, насколько сложно ваше решение, а потому ИМХО оно не наглядно и сложно в понимании для тех у кого нет ученой степени. Если с автором что случится, его менее талантливые замы исправить ничего не смогут и им придется снова создавать на форуме подобную ветку. ))