Carduelis
@Carduelis
Web-developer, front-end, js, less

Как упростить спагетти?

Преамбула

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



Последовательность изменения состояний переключателей известна, ограничена (в среднем 7-10 итераций). Количество упражнений (последовательностей) также ограничено.



Фабула

Упражнение считается выполненным, если переключаители были настроены в определенном порядке на соответствующие позиции. Текущая позиция переключателя и правильная позиция записываются в атрибуты html-тега: status и pass соответственно.

Ниже представлен код, описывающий последовательную установку определенных контролов в правильные состояния:

$('#control1').click(function() {<br>
	if ( $('#control1').attr('status') == $('#control1').attr('pass') ) {<br>
		$('#control2').click(function() {<br>
			if ( $('#control2').attr('status') == $('#control2').attr('pass') ) {<br>
				$('#control10').click(function() {<br>
					if ( $('#control10').attr('status') == $('#control10').attr('pass') ) {<br>
						$('#control1').click(function() {<br>
							if ( $('#control1').attr('status') == 3 ) {<br>
								$('#control9').click(function() {<br>
									if ( $('#control9').attr('status') == $('#control9').attr('pass') ) {<br>
										alert('Упражнение выполнено верно');<br>
									} // end if // control9<br>
								});<br>
							} // end if // control1 == 3<br>
						});<br>
					} // end if // control10<br>
				});<br>
			} // end if // control2<br>
		});<br>
	} // end if // control1<br>
});<br>




Вопрос

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



Например, верхние спагетти приобрели бы вид:

megaFunction(#control1, #control2, #control10, #control1 == 3, #control9, 'Упражнение выполнено');<br>
  • Вопрос задан
  • 4086 просмотров
Пригласить эксперта
Ответы на вопрос 7
Вешайте обработчики на контролы сразу. Создайте массив аля flow / steps / stack. А дальше как вариант — контролу присваиваете индекс (или шаг), а обработчик проверяет, если индекс контрола совпадает с текущем на стеке — проверяем и если правильно добавляем в стек, и тем самым переходом на след. индекс/шаг.
Ответ написан
Комментировать
FilimoniC
@FilimoniC
function Check {
if not (case a) return false
if not (case b) return false
if not (case c) return false
return true
}

И линейно, и лишний код после ретурна не выполняется
Ответ написан
Комментировать
hell0w0rd
@hell0w0rd
Просто разработчик
создать событие и на него повесить обработчики?
Ну или то что принимает мега функция обработать рекурсивно
Ответ написан
Комментировать
function run(){
  var args=$.map(arguments,function(arg,i){
    switch(typeof arg){
      case 'number':arg=[arg];
      case 'object':
        var el=$('#control'+arg[0]),cond=arg[1];
        return function(){
          el.click(function(){
            if(el.attr('status')==(cond==null?el.attr('pass'):cond)){
              el.unbind('click');
              args[i+1]()}})}}
    return arg});
  args[0]()}

run(1,2,10,1,[9,3],alert.bind(null,'Упражнение выполнено верно'))
Ответ написан
Suvitruf
@Suvitruf
Java/node.js/game-dev
Извиняюсь, проверить сейчас не могу код, пишу на коленке.

function megaFunction(el, list){
  $('#'.el).click(function() {
    if ( $('#'.el).attr('status') == $('#'.el).attr('pass') ) {
      //копируем массив
      var newList = list.slice(0); 
      //удаляем первый элемент
      newList.splice(0,1);
      if(newList.length != 1)
        megaFunction(list[0], newList);
      else
        //если последний элемент, то выводим сообщение об успехе
        alert(newList[0]);
     }
  });
}

megaFunction('control1', ['control2', 'control10', 'Упражнение выполнено']);


То есть, передаём в наш метод список элементов. Первый элемент — тот, для которого клик вызываем. А далее рекурсивно всё, пока не останется один элемент.
1) Можно и вообще без первого элемента, передавать только массив, где будем кликать по первому элементу.
2) Сейчас проверка только с полем attr('pass'), если хотите свой условие, то немного модифицируйте код.

Я лишь саму идею донести хотел.
Ответ написан
Комментировать
Наверное, я не правильно понял задачу. Если поясните, на примере, то помогу. Задача-то вроде как не сложная.
Я понял так, что нужно проверить у каждого выключателя атрибут status и сверить с pass.
Если так, то делается просто:
1) добавляем к каждому контролу class=«control»
2) пишем функцию:
function isCheckPassed() {
    //  Получаем все контролы
    var controls = document.getElementsByClassName('control');

    // Пробегаемся по каждому контролу
    for(var i=0; i<controls.length; i++) { 
        // Если значения status не равно pass, то возвращаем false
        if (controls[i].getAttribute("data-status") != controls[i].getAttribute("data-pass")) return false;
    }

    // Если не было ни одного false, то значит true.
    return true;
}


P.s^ хранить ответы в атрибутах — не есть гуд. Если нужны советы с этим, пишите, помогу.
P.s.s^ если задачу понял не правильно, прошу прощения.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы