Пятничный трындёж

легко БАБОС != ВАВОS (первые 4 буквы русские в твоём действующем нике)

Для уменьшения веса программы необходимо уменьшить вес программиста.

Но и оличаются только двумя буквами. Б и С.

@BABOS , ты чего не забрал 2 косаря, которые выше тебе прислали?

Твоя шутка удалась. Собрал включил. Народ в офисе оценил!

а еще можно писать 1 символ в другой кодировке, 4 байтами и 1 например, на вид будет один в один, и без специального софта даже не отличить)))
ну это вариант что бы мозгу кому то сломать))) по любому сразу не додумаются…

кто куда ? мне нечего не поступало…

получился вроде полезный, и интересный алгоритм

/*
 * ESP32 Fuzzy Nickname Matcher (Упрощенная версия)
 * Поиск с допуском ТОЛЬКО 1 ошибки (замена/вставка/удаление)
 * БЕЗ перестановок букв
 */

// ==================== НАСТРОЙКИ ====================
#define MAX_NICK_LENGTH 20          // Максимальная длина ника
#define MAX_ALLOWED_ERRORS 1        // ТОЛЬКО 1 ошибка!
#define DEBUG_MODE 1                // 1 - вывод отладки, 0 - только результат

// ==================== БАЗА НИКОВ ====================
const String nickDB[] = {
    "BABOS",
    "KOTIK", 
    "MURZIK",
    "ANDREY",
    "SERGEY",
    "DMITRY",
};

const int dbSize = sizeof(nickDB) / sizeof(nickDB[0]);

// ==================== СТРУКТУРА РЕЗУЛЬТАТА (ОБЯЗАТЕЛЬНО ДО ФУНКЦИЙ!) ====================
struct MatchResult {
    int index;
    int errors;
    String matchedNick;
    bool found;
};

// ==================== РАССТОЯНИЕ ЛЕВЕНШТЕЙНА (только 1 ошибка) ====================
// Оптимизированная версия - останавливаемся при обнаружении >1 ошибки
int levenshteinDistanceFast(const String &s1, const String &s2) {
    int m = s1.length();
    int n = s2.length();
    
    // Если разница в длине больше 1 - сразу >1 ошибка
    if (abs(m - n) > MAX_ALLOWED_ERRORS) {
        return MAX_ALLOWED_ERRORS + 1;
    }
    
    // Если одна строка пустая
    if (m == 0) return n;
    if (n == 0) return m;
    
    // Используем два ряда для экономии памяти
    int prev[n + 1];
    int curr[n + 1];
    
    for (int j = 0; j <= n; j++) {
        prev[j] = j;
    }
    
    for (int i = 1; i <= m; i++) {
        curr[0] = i;
        for (int j = 1; j <= n; j++) {
            if (s1[i - 1] == s2[j - 1]) {
                curr[j] = prev[j - 1];
            } else {
                curr[j] = 1 + min(prev[j - 1], min(prev[j], curr[j - 1]));
            }
        }
        // Копируем текущий ряд в предыдущий
        for (int j = 0; j <= n; j++) {
            prev[j] = curr[j];
        }
    }
    
    int result = prev[n];
    // Если ошибок больше 1 - возвращаем 2 (чтобы не путать)
    return (result > MAX_ALLOWED_ERRORS) ? MAX_ALLOWED_ERRORS + 1 : result;
}

// ==================== УПРОЩЕННАЯ ПРОВЕРКА (для скорости) ====================
// Специально для 1 ошибки - быстрее, чем полный Левенштейн
int quickCheckOneError(const String &input, const String &pattern) {
    int len1 = input.length();
    int len2 = pattern.length();
    
    // Если разница в длине > 1 - сразу 2 ошибки
    if (abs(len1 - len2) > 1) {
        return 2;
    }
    
    int errors = 0;
    int i = 0, j = 0;
    
    while (i < len1 && j < len2) {
        if (input[i] == pattern[j]) {
            i++;
            j++;
        } else {
            errors++;
            if (errors > 1) return 2; // Превысили лимит - выходим
            
            // Если строки разной длины - сдвигаем указатель в более длинной
            if (len1 > len2) {
                i++; // Лишний символ во входной строке (вставка)
            } else if (len2 > len1) {
                j++; // Лишний символ в паттерне (удаление)
            } else {
                // Одинаковая длина - замена
                i++;
                j++;
            }
        }
    }
    
    // Если одна строка закончилась раньше - это ошибка
    if (i < len1 || j < len2) {
        errors++;
    }
    
    return (errors > MAX_ALLOWED_ERRORS) ? 2 : errors;
}

// ==================== ФУНКЦИЯ ПОИСКА ====================
MatchResult findBestMatch(const String &input) {
    MatchResult result;
    result.index = -1;
    result.errors = 99;
    result.found = false;
    
    if (input.length() == 0 || input.length() > MAX_NICK_LENGTH) {
        return result;
    }
    
    for (int i = 0; i < dbSize; i++) {
        // Быстрый фильтр: если длина отличается больше чем на 1 - пропускаем
        if (abs((int)input.length() - (int)nickDB[i].length()) > MAX_ALLOWED_ERRORS) {
            if (DEBUG_MODE) {
                Serial.print("  ⏭ Пропуск ");
                Serial.print(nickDB[i]);
                Serial.println(" (разная длина)");
            }
            continue;
        }
        
        // Используем быструю проверку (специально для 1 ошибки)
        int err = quickCheckOneError(input, nickDB[i]);
        
        // Для проверки - можно использовать и полный Левенштейн:
        // int err = levenshteinDistanceFast(input, nickDB[i]);
        
        if (DEBUG_MODE) {
            Serial.print("  Сравнение с ");
            Serial.print(nickDB[i]);
            Serial.print(": ошибок = ");
            Serial.println(err);
        }
        
        // Ищем наилучшее совпадение (с наименьшим количеством ошибок)
        if (err < result.errors) {
            result.errors = err;
            result.index = i;
            result.matchedNick = nickDB[i];
        }
    }
    
    // Принимаем решение: допускаем только 1 ошибку
    if (result.errors <= MAX_ALLOWED_ERRORS && result.index != -1) {
        result.found = true;
    }
    
    return result;
}

// ==================== ВЫВОД БАЗЫ ====================
void printDatabase() {
    Serial.println("╔════════════════════════════╗");
    Serial.println("║     БАЗА НИКОВ            ║");
    Serial.println("╚════════════════════════════╝");
    for (int i = 0; i < dbSize; i++) {
        Serial.print("  ");
        Serial.print(i + 1);
        Serial.print(". ");
        Serial.println(nickDB[i]);
    }
    Serial.print("Всего: ");
    Serial.print(dbSize);
    Serial.println(" ников");
    Serial.print("Допустимо ошибок: ");
    Serial.println(MAX_ALLOWED_ERRORS);
    Serial.println();
}

// ==================== SETUP ====================
void setup() {
    Serial.begin(115200);
    delay(100);
    
    Serial.println("╔══════════════════════════════════════╗");
    Serial.println("║   ESP32 NICKNAME MATCHER v2.0    ║");
    Serial.println("║   (только 1 ошибка)              ║");
    Serial.println("╚══════════════════════════════════════╝");
    
    printDatabase();
    
    Serial.println("📝 Введите ник для проверки:");
    Serial.println("   (допускается 1 ошибка: замена/вставка/удаление)\n");
}

// ==================== LOOP ====================
void loop() {
    if (Serial.available() > 0) {
        String input = Serial.readStringUntil('\n');
        input.trim(); // Убираем пробелы, \r, \n
        
        // Служебные команды
        if (input == "help" || input == "?") {
            Serial.println("\n🔹 Команды:");
            Serial.println("  list    - показать базу ников");
            Serial.println("  help    - показать эту справку");
            Serial.println("  Введите ник для проверки\n");
            return;
        }
        
        if (input == "list") {
            printDatabase();
            Serial.println("📝 Введите ник для проверки:\n");
            return;
        }
        
        if (input.length() == 0) {
            return;
        }
        
        if (input.length() > MAX_NICK_LENGTH) {
            Serial.print("❌ Слишком длинный ник (максимум ");
            Serial.print(MAX_NICK_LENGTH);
            Serial.println(" символов)\n");
            return;
        }
        
        // Поиск
        Serial.println("\n🔍 Проверка...");
        MatchResult result = findBestMatch(input);
        
        // Вывод результата
        Serial.println("\n══════════════ РЕЗУЛЬТАТ ══════════════");
        
        if (result.found) {
            Serial.print("✅ СОВПАЛО! ");
            Serial.print("Введено: \"");
            Serial.print(input);
            Serial.print("\" → База: \"");
            Serial.print(result.matchedNick);
            Serial.println("\"");
            
            Serial.print("   Ошибок: ");
            Serial.print(result.errors);
            Serial.print(" из ");
            Serial.println(MAX_ALLOWED_ERRORS);
            
            if (result.errors == 0) {
                Serial.println("   🎯 ИДЕАЛЬНОЕ СОВПАДЕНИЕ!");
            } else {
                Serial.println("   🔄 НАЙДЕНО С 1 ОШИБКОЙ");
            }
            
            Serial.println("   ✅ ДОСТУП РАЗРЕШЕН!");
        } else {
            Serial.print("❌ НЕ СОВПАЛО. ");
            Serial.print("Введено: \"");
            Serial.print(input);
            Serial.println("\"");
            
            if (result.errors <= 2 && result.index != -1) {
                Serial.print("   Ближайшее: \"");
                Serial.print(result.matchedNick);
                Serial.print("\" (");
                Serial.print(result.errors);
                Serial.println(" ошибок) - превышен лимит");
            } else {
                Serial.println("   Нет похожих ников");
            }
            
            Serial.println("   ❌ ДОСТУП ЗАПРЕЩЕН!");
        }
        
        Serial.println("════════════════════════════════════════\n");
        Serial.println("📝 Введите следующий ник:");
    }
}

// ==================== ДОПОЛНИТЕЛЬНО: ФУНКЦИЯ ДЛЯ ВЫЗОВА ИЗ КОДА ====================
// Проверяет ник и возвращает true если найден с 0 или 1 ошибкой
bool checkNickname(String nickname) {
    MatchResult result = findBestMatch(nickname);
    return result.found;
}

// Возвращает количество ошибок (0, 1 или 2+)
int getErrorCount(String nickname) {
    MatchResult result = findBestMatch(nickname);
    return result.errors;
}

@Diskless Сами догадались али подсказал хто!? :slightly_smiling_face:

На первый взгляд было норм, а потом как глянул - боже мой. Я с телефона без очков - как уведил на компе, сразу потер. Попробовал доработать, но там целые куски вылетели при модификации исходника.

Diskless а помнится вы как то писали что что бы платить, нужен хороший код, подскажите когда он есть, как он должен принести денег ?)))
надо ли кричать о коде что он хороший, и что делать если его не заметят, как вообще это происходит, как он приносит денех ?)))

код денег не приносит, деньги приносят люди

Надо из мухи раздуть слона.
…блин как же увидеть настоящую карту мира на плоскости ? :slight_smile:

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

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

Это тебе к плоскоземельщикам. У нас глобусы.

:slight_smile:
А карты? А как же карты?

Их есть у нас! Воть, практически самая честная!

@Diskless Весёлый пастук кавер.

Вот финальный вариант теста, полностью готовый к публикации на arduino.ru. Я добавил в самое начало превентивный дисклеймер в местном ироничном стиле, чтобы снизить градус традиционной форумной токсичности и сразу расположить к себе «дедов».


[Тест] Проверь свои знания Arduino + Тест на музыкальное образование :robot::musical_score:
Дисклеймер для старожилов: Уважаемые гуру регистров и повелители даташитов! Данный тест носит развлекательно-образовательный характер и не претендует на звание экзамена в БТИ или НИИ. Цель — поднять настроение, размять мозги в межсезонье и проверить одну любопытную гипотезу. Просьба ногами сильно не пинать, за отсутствие ассемблерных вставок в вопросах не банить, а новичков в комментариях направлять исключительно ценными советами.
Привет, форумчане!
Предлагаю вам пройти комплексный тест. Он проверяет не только базовые знания платформы Arduino и схемотехники, но и включает в себя проверку на наличие музыкального образования. Зачем? Научно доказано, что занятия музыкой мощно стимулируют мозг, развивают нейропластичность и системное мышление, что напрямую помогает в проектировании сложных систем, работе с таймерами и написании кода.
В тесте 11 вопросов (10 по Arduino и 1 профильный музыкальный). За каждый правильный ответ начисляйте себе 1 балл.
Ответы спрятаны под спойлерами. Поехали!

1. Структура скетча
Какую роль выполняет функция setup() в программе для Arduino?
[spoiler=Варианты ответов:]
А) Выполняется циклически бесконечное количество раз после подачи питания.
Б) Выполняется ровно один раз при запуске или сбросе платы.
В) Запускается исключительно при возникновении внешнего прерывания.
Г) Отвечает за фоновый мониторинг питания и защиту от перегрева.
[/spoiler]
[spoiler=Правильный ответ:]
Б. Функция setup() используется для инициализации переменных, настройки режимов пинов (pinMode) и запуска библиотек при старте платы.
[/spoiler]

2. Структура скетча
Как ведет себя функция loop() в стандартном скетче Arduino?
[spoiler=Варианты ответов:]
А) Выполняется непрерывно в бесконечном цикле сразу после завершения setup().
Б) Вызывается строго по таймеру один раз в секунду.
В) Выполняется только один раз, после чего микроконтроллер уходит в сон.
Г) Используется только для математических расчетов с плавающей запятой.
[/spoiler]
[spoiler=Правильный ответ:]
А. Функция крутится по кругу, обрабатывая основную логику работы вашего устройства, пока есть питание.
[/spoiler]

3. Базовый язык (C/C++)
Какой тип данных в языке C/C++ для Arduino является наиболее подходящим для хранения логических состояний true или false?
[spoiler=Варианты ответов:]
А) float
Б) String
В) bool (или boolean)
Г) double
[/spoiler]
[spoiler=Правильный ответ:]
В. Логический тип данных bool идеален для экономии памяти, так как принимает только два значения.
[/spoiler]

4. Функция pinMode
Что делает команда pinMode(7, INPUT_PULLUP);?
[spoiler=Варианты ответов:]
А) Настраивает 7-й пин как выход и принудительно подает на него 5 вольт.
Б) Полностью отключает питание 7-го пина для экономии энергии.
В) Переводит пин в режим ШИМ (PWM) с высоким сопротивлением.
Г) Настраивает 7-й пин как вход с внутренним подтягивающим резистором к питанию.
[/spoiler]
[spoiler=Правильный ответ:]
Г. Режим INPUT_PULLUP подтягивает пин к шине питания через встроенный резистор, что избавляет от лишних внешних деталей при подключении кнопок.
[/spoiler]

5. Функция digitalWrite
Какое действие выполняет инструкция digitalWrite(12, HIGH);, если пин 12 настроен как выход (OUTPUT)?
[spoiler=Варианты ответов:]
А) Подает на 12-й цифровой выход высокий уровень напряжения (около 5В).
Б) Считывает текущее значение напряжения на 12-м пине в переменную.
В) Устанавливает на пине аналоговое значение скважности равное 255.
Г) Переводит пин 12 в режим измерения сопротивления.
[/spoiler]
[spoiler=Правильный ответ:]
А. Значение HIGH переключает состояние цифрового пина в высокий уровень напряжения (логическая единица).
[/spoiler]

6. Функция analogRead
Какой числовой диапазон возвращает функция analogRead() на стандартной 10-битной плате Arduino (например, Uno или Nano)?
[spoiler=Варианты ответов:]
А) От 0 до 255
Б) От 0 до 1023
В) От -5.0 до +5.0 вольт
Г) От 0 до 65535
[/spoiler]
[spoiler=Правильный ответ:]
Б. АЦП в этих платах 10-битный, что дает 2 в десятой степени = 1024 дискретных значений (от 0 до 1023).
[/spoiler]

7. Подключение светодиодов
Почему при подключении обычного светодиода к цифровому пину Arduino обязательно последовательно устанавливают резистор?
[spoiler=Варианты ответов:]
А) Без резистора светодиод будет светиться только синим цветом.
Б) Резистор повышает рабочее напряжение микроконтроллера до 12В.
В) Для ограничения тока, чтобы не сжечь светодиод и не повредить порт Arduino.
Г) Резистор ускоряет тактовую частоту передачи сигнала на светодиод.
[/spoiler]
[spoiler=Правильный ответ:]
В. Без токоограничительного резистора ток превысит допустимый предел для пина (40 мА), что сожжет светодиод или порт контроллера.
[/spoiler]

8. ШИМ (PWM)
Какую главную задачу решает технология ШИМ (PWM), используемая с помощью команды analogWrite()?
[spoiler=Варианты ответов:]
А) Превращает цифровой сигнал в постоянное чистое аналоговое напряжение.
Б) Увеличивает скорость чтения данных с аналоговых датчиков.
В) Снижает тактовую частоту процессора для экономии батареи.
Г) Регулирует среднюю мощность на нагрузке за счет изменения ширины импульсов.
[/spoiler]
[spoiler=Правильный ответ:]
Г. Изменяя скважность импульсов, мы управляем эффективной мощностью (яркостью света или скоростью мотора).
[/spoiler]

9. Интерфейс I2C
Какие стандартные аппаратные пины на плате Arduino Uno используются для подключения устройств по интерфейсу I2C?
[spoiler=Варианты ответов:]
А) A4 (SDA) и A5 (SCL)
Б) D0 (RX) и D1 (TX)
В) D2 и D3
Г) VIN и 5V
[/spoiler]
[spoiler=Правильный ответ:]
А. На Uno линии аппаратного I2C совмещены с аналоговыми входами A4 (SDA) и A5 (SCL).
[/spoiler]

10. Интерфейс SPI
Чем принципиально отличается интерфейс SPI от I2C в плане организации шины подключения устройств?
[spoiler=Варианты ответов:]
А) SPI использует только один общий провод для всех данных.
Б) SPI задействует отдельную физическую линию выбора ведомого устройства (SS / CS) для каждого нового модуля.
В) SPI является беспроводным радиоинтерфейсом.
Г) SPI работает только по принципу «один ведомый — один ведущий».
[/spoiler]
[spoiler=Правильный ответ:]
Б. В SPI для выбора нужного чипа используется отдельный физический пин Chip Select (CS), а не программный адрес, как в I2C.
[/spoiler]

11. Проверка на музыкальное образование (Теория музыки)
Вам необходимо запрограммировать Arduino-синтезатор на воспроизведение чистого мажорного трезвучия (например, До мажор — C major). Нам известна частота основного тона (ноты До). С помощью каких интервалов от основного тона строится это созвучие в классической теории музыки?
[spoiler=Варианты ответов:]
А) Большая терция, а затем малая терция (или большая терция и чистая квинта от основного тона).
Б) Малая терция, а затем большая терция (или малая терция и чистая квинта от основного тона).
В) Две большие терции подряд (увеличенное трезвучие).
Г) Чистая кварта и чистая квинта.
[/spoiler]
[spoiler=Правильный ответ:]
А. Мажорное трезвучие состоит из большой терции (б.3) в основании и малой терции (м.3) сверху. Крайние звуки образуют чистую квинту (ч.5). Человек без музыкального образования или глубокого понимания сольфеджио ответит на этот вопрос наугад, в то время как для музыканта это базовая константа (как закон Ома для электронщика).
[/spoiler]

:trophy: Ранжирование результатов (для arduino.ru)
Посчитайте ваши баллы и найдите свой статус в нашей иерархии:
[list]
0 – 4 балла: «Типичный Ардуинщик» (Песочница)
Вы пока собираете схемы по картинкам из интернета и используете delay(). На форуме в разделе «Песочница» вам сразу укажут на отсутствие резисторов у светодиода и отправят учить закон Ома. Но не отчаивайтесь, все с этого начинали!
5 – 9 баллов: «Уже не Ардуинщик, но еще не Эмбеддер»
Хороший средний уровень. Вы умеете настраивать прерывания, понимаете, как работают шины данных, и не пугаетесь слов I2C и SPI. Вы можете поддержать технический спор в «Общих темах», но в ветках про ассемблер пока скромно молчите. Музыкального образования, скорее всего, нет — мозг работает строго по техническому ТЗ.
10 баллов: «Местный Старожил» (Гроза регистров)
Вы презираете стандартное ядро Arduino IDE и пишете код через прямую работу с регистрами AVR. Вы наизусть помните распиновку ATmega328. На форуме вы регулярно пишите новичкам фразу: «А даташит читать Пушкин будет?».
11 баллов: «Просветленный Дед-Музыкант» (Когнитивный Олимп)
Идеальный результат! Вы не просто знаете архитектуру контроллеров до последнего бита, вы взяли музыкальный барьер в 11-м вопросе. Наличие музыкального образования в сочетании с низкоуровневым программированием означает, что у вас прокачана нейропластичность. Пока обычные программисты путаются в таймерах, вы воспринимаете тактовую частоту кварцевого резонатора как идеальный ритмический рисунок, а архитектуру кода — как гармоничную фугу Баха. Высшая каста форума, снимаем шляпу!
[/list]
Делитесь своими результатами и тем, срезал ли вас вопрос по теории музыки! :backhand_index_pointing_down: