Этюд на тему "Угадайка"

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

1. Код написать и сам смогу, просьба не отсылать в раздел "Ищу исполнителя" ;)

2. Идеи алгоритма вроде как формируются, но пока тупые. Может кто подскажет более умный АЛГОРИТМ.

Итак, задачка.

Есть 12 кнопок. По рандому выбирается 4 цифры из 12 (не повторяющиеся) в интервале 1-9,A,B,C.

Примерно так:

    while(!KBDread())
    {
      randomSeed(millis());
      delay(1000);
    }
    while(i<4)
    {
      ChemodanKey[i]=random(1,13);
      switch(i)
      {
        case 0:
          i++;
        break;
        case 1:
          if(ChemodanKey[i]!=ChemodanKey[0]){i++;}
        break;
        case 2:
          if(ChemodanKey[i]!=ChemodanKey[0]&&ChemodanKey[i]!=ChemodanKey[1]){i++;}
        break;
        case 3:
          if(ChemodanKey[i]!=ChemodanKey[0]&&ChemodanKey[i]!=ChemodanKey[1]&&ChemodanKey[i]!=ChemodanKey[2]){i++;}
        break;
      }
    }

Хотя уверен не оптимальное решение.

Дальше алгоритм простой:

если нажата кнопка из списка ЧемоданКей - запоминаем ее (и показываем на экране), ждем нажатие следующей.

Если следующая и далее кнопки из списка - продолжаем пока не будет угадано все 4 цифры (показ и гимн в динамик ;)

Если ошибка - цифра не из списка - сирена, сброс показа дисплея и блокировка на Х минут.

После окончания блокировки цикл начинается сначала.

Идеи?

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

at0mix пишет:

Примерно так:

    while(!KBDread())
    {
      randomSeed(millis());
      delay(1000);
    }
    while(i<4)
    {
      ChemodanKey[i]=random(1,13);
      switch(i)
      {
        case 0:
          i++;
        break;
        case 1:
          if(ChemodanKey[i]!=ChemodanKey[0]){i++;}
        break;
        case 2:
          if(ChemodanKey[i]!=ChemodanKey[0]&&ChemodanKey[i]!=ChemodanKey[1]){i++;}
        break;
        case 3:
          if(ChemodanKey[i]!=ChemodanKey[0]&&ChemodanKey[i]!=ChemodanKey[1]&&ChemodanKey[i]!=ChemodanKey[2]){i++;}
        break;
      }
    }

i не инициализирована. seed вызывается пачку раз зачем-то, причём вызывается как-то странно. Если это начало работы программы, то он там практически всегда одинаковый будет. Если уж нужен seed - надо брать analogRead с висящего в воздухе пина. Дальнейший выбор уж больно заморочный, но это Ваш выбор.

at0mix пишет:

1. Код написать и сам смогу, просьба не отсылать в раздел "Ищу исполнителя" ;)

Успехов!

at0mix пишет:

Идеи?

Какие тут идеи? Идея одна - садиться, да делать.

 

Logik
Offline
Зарегистрирован: 05.08.2014

Я бы это скорей так писал. Код не проверялся на компилируемость

for(byte i=0;i<4;)
{
  byte a=random(1,13);
  for(byte j=0;j<i;j++)
  {
    if(ChemodanKey[j]==a)
    {
      a=0;//повтор!!!
      break;
    }
  }
  if(a) ChemodanKey[i]=a;
  else continue;
  i++;
}

.Или хотяб свитч причесал

switch(i)
  {
    case 3:
      if(ChemodanKey[i]==ChemodanKey[2]) break;
    case 2:
      if(ChemodanKey[i]==ChemodanKey[1]) break;
    case 1:
      if(ChemodanKey[i]==ChemodanKey[0]) break;
    case 0:
      i++;
  }

 

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

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

А второй вариант может неправильно отработать:

если i==0 то все понятно - записываем первыую цифру, если 1 - то сравниваем с первой, если 2 - то нужно сравнивать с первой и второй на совпадение, а для 3 - со всеми тремя предыдущими - т.к. цифры должны быть уникальными и несовпадающими.

Logik
Offline
Зарегистрирован: 05.08.2014

at0mix пишет:

 если 2 - то нужно сравнивать с первой и второй на совпадение, а для 3 - со всеми тремя предыдущими - т.к. цифры должны быть уникальными и несовпадающими.

Дак учтено. Если при 2 сравнение свыявило совпадение, то бреак, иначе идем далее а далее случай 1, те проверка первого числа.

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

Вот что получилось - с учетом того что это процедура из части проекта - те используются глобалы за скобками:

void StartMODE3(void)// режим ЧЕМОДАН
{
//при старте выбираем время блокировки
//на экране bd (block delay) в пятиминутках
//выбор на кнопках от 1 до 12 по 5 минут == от 5 до 60 минут
//затем инициализация датчика случайных чисел SE
//генерируется 4 цифры кода, выводятся на экран на 2 сек
//если нажата неправильная цифра - блокировка на время bd минут и сирена
//если все цифры угаданы - звук и переход на новую игру
//если найден ключ ТМ - сбрасываем все включая звук, найденные ключи
//если с ключем ТМ наата любая кнопка - рестарт игры
  while(1)
  {
    byte EndGAME=0;
    byte i=1;
    byte j=0;
    byte buff=0;
    byte ChmNM=0;// цифра угадана
    byte numKey=0;// количество угаданных цифр
    byte ChemodanRead[4]={0,0,0,0};//буфер

    //инициализация параметров игры
    tm1637.clearDisplay();//на экран выводим bd
    tm1637.display(0,11);
    tm1637.display(1,13);
    buff=KBDread();
    do//ждем нажатие на кнопку
    {
      buff=KBDread();//читаем кнопки
      TimeCH=buff*5;//устанавливаем тайм-аут для ошибки набора *5 мин
      tm1637.display(3,buff);// выводим число 5-минуток тайм-аута
    }while(!buff);//ждем нажатие на кнопку
    delay(4000);
    tm1637.clearDisplay();//на экран выводим 5Е
    tm1637.display(0,5);
    tm1637.display(1,14);
    while(!KBDread())//ждем нажатие на кнопку
    {
      randomSeed(millis());//инициализируем счетчик рандома
      delay(200);
    }
    ChemodanKey[0]=random(1,13);//из списка 1-12 первая цифра
    while(i<4)//набираем 4 цифры
    {
      buff=random(1,13);//из списка 1-12 следующая цифра
      ChmNM=1;
      for(j=0;j<i;j++)
      {
        if(ChemodanKey[j]==buff)//Если цифра повторяется
        {
          ChmNM=0;//сбрасываем счетчик - идем на повтор
        }
      }
      if (ChmNM)//если цифра новая - запоминаем, ищем следующую
      {
        ChemodanKey[i]=buff;
        i++;
      }
    }
    ChmNM=0;
    for (i=0;i<4;i++)
    {
      tm1637.display(i,ChemodanKey[i]);//выводим установленные цифры
                        Serial.print(ChemodanKey[i],HEX); //для отладки
    }
                        Serial.println(); //для отладки
    SirenaOUT;//мявкаем в динамик
    delay(2000);

    tm1637.clearDisplay();//стираем все
    tm1637.display(0,0);//на экран 0
    numKey=0;
    while(!EndGAME)//пока EndGAME==0 крутим цикл
    {
      if(ds.reset()) // если обнаружен ключ сбрасываем все в 0
      {
            for(i=0;i<=numKey;i++)
            {
              ChemodanRead[i]=0;//сбросили хранилище угаданных ключей
            }
            ChmNM=0;//изменили статус на 0
            numKey=0;//число угаданных 0
            tm1637.clearDisplay();//стираем все
            tm1637.display(0,0);//на экран 0
            if (KBDread())//если нажата кнопка стартуем новую игру
            {
              EndGAME=1;
            }
      }
      buff=KBDread();//читаем клавиатуру
      if(buff)//если кнопка нажата
      {
        ChmNM=0;
        for(i=0;i<4;i++)// проверяем цифру
        {
          if(buff==ChemodanKey[i])//если цифра есть в коде
          {
            ChmNM=1;//изменили статус на 1
            ChemodanRead[numKey]=ChemodanKey[i];//запомнили угаданную цифру
            SirenaOUT();//мявкнули в динамик
            tm1637.display(numKey,ChemodanRead[numKey]);//вывели на экран угаданную цифру
          }
        }
        if(!ChmNM)//если не угадали
        {
            for(i=0;i<=numKey;i++)
            {
              ChemodanRead[i]=0;//сбросили хранилище угаданных ключей
            }
            ChmNM=0;//изменили статус на 0
            numKey=0;//число угаданных 0
            tm1637.clearDisplay();//стираем все
            for(i=0;i<4;i++)
            {
              tm1637.display(i,0);//на экран 0
            }
                        Serial.println(" ERROR "); //для отладки
            PrevMillis=millis();//запоминаем первый миллс
            while(millis()-PrevMillis<TimeCH*TimeXX)//в течении ХХ минут ревем сиреной
            {
              SirenaOUT();//сирена
              delay(1000);
                        Serial.println(" ERROR 1"); //для отладки

            if(ds.reset()) // если обнаружен ключ сбрасываем все в 0
            {
              for(i=0;i<=numKey;i++)
              {
                ChemodanRead[i]=0;//сбросили хранилище угаданных ключей
              }
              PrevMillis=TimeCH*TimeXX+millis();
              ChmNM=0;//изменили статус на 0
              numKey=0;//число угаданных 0
              tm1637.clearDisplay();//стираем все
              tm1637.display(0,0);//на экран 0
              if (KBDread())//если нажата кнопка стартуем новую игру
              {
                EndGAME=1;
              }
            }
          }
          tm1637.clearDisplay();//стираем все
          tm1637.display(0,0);//на экран 0
        }else
        {
          numKey++;//если угадали - следующий номер
          delay(1000);
        }
      }
      if(numKey>3)//если угадали все 4 - гимн
      {
        SirenaOUT();
        SirenaOUT();
        SirenaOUT();
        EndGAME=1;
      }
    }
  }
}