/*************************************************************************** * Copyright (C) 2010 by ANPO Abashin.ru * * electronichealth@rambler.ru * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif /////////////////////////////////////////////////////////////////////////////////// // При компиляции с помощью gcc ключ -lm /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #define PASSWORD 36 //Допустимая длинна пароля #define REPEAT 30 //Максимальное кол-во повторений #define TIME_LIMIT 500 //Кол-во миллисекунд между нажатиями //Формат присылаемых данных struct KEY { int key; //Клавиша long long int count; //Счетчик нажатий int up_down; //Нажал или отпустил 1-нажал/0-отпустил }; //Формат эталона struct ETALON_KEY { int key; //Клавиша long long int pressing; //Нажатие long long int space; //Между нажатиями }; /////////////////////////////////////////////////////////////////////////////////// // ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ /////////////////////////////////////////////////////////////////////////////////// struct ETALON_KEY sequence_etalon [PASSWORD] = {0}; //Последовательность эталона struct ETALON_KEY sequence_etalon_temp [REPEAT][PASSWORD] = {0}; //Последовательность эталона struct KEY keys[REPEAT][PASSWORD*2] = {0}; //Нажатые клавиши int correct_sequence [PASSWORD] = {0}; //Правильная последовательность символов вспомогательная int sequence_massive [REPEAT][PASSWORD] = {0}; //Массив последовательностей клавиш вспомогательный struct KEY data[PASSWORD*2] = {0}; //Строка на идентификацию /////////////////////////////////////////////////////////////////////////////////// // Функция создания эталона /////////////////////////////////////////////////////////////////////////////////// int create_etalon (void); /////////////////////////////////////////////////////////////////////////////////// // Функция преобразования входных данных в правильную последовательность /////////////////////////////////////////////////////////////////////////////////// void data_to_sequence (void); /////////////////////////////////////////////////////////////////////////////////// // Функция выбрасывает строки с опечатками /////////////////////////////////////////////////////////////////////////////////// void delete_bad_date (void); /////////////////////////////////////////////////////////////////////////////////// // Построчный перенос данных в последовательность /////////////////////////////////////////////////////////////////////////////////// void one_string_to_sequence (int nomber); /////////////////////////////////////////////////////////////////////////////////// // Получение правильной последовательности /////////////////////////////////////////////////////////////////////////////////// void get_correct_sequence (int nomber); /////////////////////////////////////////////////////////////////////////////////// // Получение эталонной последовательности /////////////////////////////////////////////////////////////////////////////////// void create_sequence_etalon(void); /////////////////////////////////////////////////////////////////////////////////// // Получение одной эталонной последовательности /////////////////////////////////////////////////////////////////////////////////// void create_one_etalon_sequence (int nomber); /////////////////////////////////////////////////////////////////////////////////// // Удаление шумов /////////////////////////////////////////////////////////////////////////////////// void delete_noise (void); /////////////////////////////////////////////////////////////////////////////////// // Функции определения качества почерка /////////////////////////////////////////////////////////////////////////////////// int speed_press (int nomber); int speed_simbol (int nomber, int character_is_entered); char error_percent (int nomber, int character_is_entered); char percent_of_overlaps(int nomber); char unrhythmically (int nomber); char estimation (int speed_press, int speed_simbol, char error_percent, char percent_of_overlaps, char unrhythmically); int text_length (void); /////////////////////////////////////////////////////////////////////////////////// // Функция создания эталона /////////////////////////////////////////////////////////////////////////////////// int create_etalon (void) { //Преобразуем в последовательность для рассчетов data_to_sequence (); //Выбрасываем строки с опечатками delete_bad_date (); //Заполняем массив эталонных последовательностей create_sequence_etalon(); //Отбрасываем шумы в etalon, вместо них пишем TIME_LIMIT delete_noise (); //Рассчитываем эталон как среднеарифметическое значащих нажатий int i, i1; long long int pressing = 0, space = 0, pressing_sum = 0, space_sum = 0; for (i = 0; i < PASSWORD; i++) { for (i1 = 0; i1 < REPEAT; i1++) { //Подготавливаемся к среднеарифметическому if (sequence_etalon_temp[i1][i].space != 0) { space++; space_sum = space_sum + sequence_etalon_temp[i1][i].space; } if (sequence_etalon_temp[i1][i].pressing != 0) { pressing++; pressing_sum = pressing_sum + sequence_etalon_temp[i1][i].pressing; } } //Переносим значение в эталон и среднее арифметическое if ((pressing != 0) && (space != 0)) { //...если ни не равны 0 sequence_etalon[i].key = sequence_etalon_temp[i1][i].key; sequence_etalon[i].pressing = pressing_sum / pressing; sequence_etalon[i].space = space_sum / space; } pressing = 0, space = 0, pressing_sum = 0, space_sum = 0; } //Рассчитываем стабильность ввода //Подсчитываем кол-во введенных символов int character_is_entered = text_length (); char est = 0; //Средняя оценка char estim[REPEAT] = {0}; //Для рассчета средней оценки for (i = 0; i < REPEAT; i++) { //Обрабатываем вычислительными функциями int sp = speed_press (i); int ss = speed_simbol (i, character_is_entered); char ep = error_percent (i, character_is_entered); char poo = percent_of_overlaps (i); char un = unrhythmically (i); estim[i] = estimation (sp, ss, ep, poo, un); } int estim_sum = 0, estim_nomber = 0; for (i = 0; i < REPEAT; i++) { if (estim[i] != 0) { estim_nomber++; estim_sum = estim_sum + estim[i]; } } //Сумма баллов, вроде бы максимальный 25, доводим до 100 чтобы вроде как ровно. est = estim_sum / estim_nomber * 4; //Возвращаем качество почерка return (int) est; }; /////////////////////////////////////////////////////////////////////////////////// // Функция идентификации // Принимает эталон,собранную информацию,меру Евклида,стабильность // Возвращает 0-не он, 1-он,дробная часть точность ответа /////////////////////////////////////////////////////////////////////////////////// float identification (double measure, int stability) { float yes_no = 0; //Преобразуем нажатия в последовательность memcpy ((void *)&keys[0][0], (const void *)&data[0], sizeof(struct KEY)*PASSWORD*2); one_string_to_sequence (0); //Делаем последовательность из набора символов create_one_etalon_sequence (0); //Делаем эталонную последовательность //Вычисляем Евклидово расстояние между эталоном и присланными данными int i; long long int sum = 0; for (i = 0; i < PASSWORD; i++) { sum = sum + pow(sequence_etalon_temp[0][i].space - sequence_etalon[i].space, 2); sum = sum + pow(sequence_etalon_temp[0][i].pressing - sequence_etalon[i].pressing, 2); } double id_measure = 0; { double temp = (double)sum; id_measure = sqrt(temp); } //Сравниваем с присланной (максимально допустимой) мерой и определяем степень прохождения пользователя if (id_measure <= measure) yes_no = 1; //Формулу проверь (чем ниже стабильность, тем неопределеннее ответ) else { //На сколько процентов превышение char how_percent = id_measure / (measure / 100) - 100; //Уменьшаем процент на стабильность, чем выше, тем меньше уменьшаем yes_no = (float)1 - (float)how_percent / (float)100 * (float)stability / (float)100; } return yes_no; }; /////////////////////////////////////////////////////////////////////////////////// // Функция преобразования строки в последовательность /////////////////////////////////////////////////////////////////////////////////// void data_to_sequence (void) { //Передаем построчно на преобразование информации в последовательность int nomber; for (nomber = 0; nomber < REPEAT; nomber++) { one_string_to_sequence (nomber); } //Переносим sequence_massive в correct_sequence, в цикле, чтобы обойти все символы пароля for (nomber = 0; nomber < PASSWORD; nomber++) { get_correct_sequence (nomber); } }; /////////////////////////////////////////////////////////////////////////////////// // Функция удаление строк с опечатками /////////////////////////////////////////////////////////////////////////////////// void delete_bad_date (void) { int i, i1, flag = 0; //Найти строки в sequence_massive, которые не соответствуют correct_sequence for (i = 0; i < REPEAT; i++) { for (i1 = 0; i1 < PASSWORD; i1++) { if (correct_sequence[i1] != sequence_massive[i][i1]) { flag = 1; break; } } if (flag == 1) { //Если флаг на последовательность выставлен //... удаляем в keys строку с таким же индексом memset((void *)&keys[i][0],0,sizeof(struct KEY)*PASSWORD*2); } flag = 0; } }; /////////////////////////////////////////////////////////////////////////////////// // Получение правильной последовательности /////////////////////////////////////////////////////////////////////////////////// void get_correct_sequence (int nomber) { int i, i1, flag = 0; int temp_massive [REPEAT][2] = {0}; //Вспомогательный массив по вертикале и кол-во for (i = 0; i < REPEAT; i++) { //Обходим sequence_massive по вертикале чтобы заполнить temp_massive if (sequence_massive [i][nomber] == 0) continue; for (i1 = 0; i1 < REPEAT; i1++) { if (temp_massive[i1][0] == sequence_massive [i][nomber]) { //Такая буква уже есть temp_massive[i1][1]++; //Увеличиваем счетчик попаданий flag = 1; break; } } if (flag == 0) { //Такой буквы не нашлось, добавляем for (i1 = 0; i1 < REPEAT; i1++) { if (temp_massive[i1][0] == 0) { //Пустая клавиша, заполняем temp_massive[i1][1]++; //Увеличиваем счетчик попаданий temp_massive[i1][0] = sequence_massive [i][nomber]; break; } } } flag = 0; } //Всплываем пузырьковым методом наиболее часто встречающийся символ for (i1 = REPEAT; i1 > 0; i1--) { if (temp_massive[i1][1] > temp_massive[i1-1][1]) { //Если клавиша выше больше temp_massive[i1-1][1] = temp_massive[i1][1]; temp_massive[i1-1][0] = temp_massive[i1][0]; break; } } //Перемещаем полученный символ в correct_sequence correct_sequence [nomber] = temp_massive[0][0]; } /////////////////////////////////////////////////////////////////////////////////// // Построчный перенос данных в последовательность /////////////////////////////////////////////////////////////////////////////////// void one_string_to_sequence (int nomber) { int temp_massive [PASSWORD] = {0}; //Вспомогательный массив int max_pass_length = PASSWORD * 2; int max_repeat = REPEAT; int i; //Счетчик нажатий во введенной последовательности int i1; //Счетчик для обхода вспомогательного temp_massive int flag = 0; //Флаг найдена ли такая клавиша int smc = 0; // if (keys[nomber][0].count == 0) keys[nomber][0].count = 1; //Если нулевой элемент имеет время 0, подправляем на 1 млс. for (i = 0; i < max_pass_length; i++) { //------------------------------------------------------------------------------ //Если новая клавиша и нажатие пишем её в sequence_massive и в temp_sequence //Если нажатие и клавиша такая есть, фильтруем её //Если отжатие и клавиша такая есть, убираем клавишу из sequence_massive //------------------------------------------------------------------------------ if (keys[nomber][i].count != 0) { //Запись активна //Обходим массив состояния клавиш for (i1 = 0; i1 < PASSWORD; i1++) { if (temp_massive[i1] == keys[nomber][i].key) { //Если клавиша такая есть flag = 1; if (keys[nomber][i].up_down == 0) temp_massive[i1] = 0; //... и отжатие,убираем такую клавишу из temp_massive break; //... и опять нажатие, просто прекращаем цикл } } //Если клавиша не была найдена if (flag == 0) { for (i1 = 0; i1 < PASSWORD; i1++) { //...пишем её в temp_sequence if (temp_massive[i1] == 0) { temp_massive[i1] = keys[nomber][i].key; break; } } //...пишем её в sequence_massive sequence_massive[nomber][smc] = keys[nomber][i].key; smc++; } flag = 0; //иначе отбросит все остальные записи } //конец активной записи } }; /////////////////////////////////////////////////////////////////////////////////// // Получение эталонной последовательности /////////////////////////////////////////////////////////////////////////////////// void create_sequence_etalon(void) { //Переносим keys в sequence_etalon построчно int max_repeat = REPEAT; int i; for (i = 0; i < max_repeat; i++) { create_one_etalon_sequence (i); } }; /////////////////////////////////////////////////////////////////////////////////// // Получение одной эталонной последовательности /////////////////////////////////////////////////////////////////////////////////// void create_one_etalon_sequence (int nomber) { //Вспомгательная структура struct ETALON_KEY_TEMP { int key; //Клавиша long long int press_down; //Нажатие long long int press_up; //Отжатие long long int space; //Между нажатиями }; //Сначало заполняем её struct ETALON_KEY_TEMP ekp[PASSWORD] = {0}; int i, i1, flag = 0; int max_pass_length = PASSWORD * 2; //Признак неправильной строки первый полностью нулевой символ if ((keys[nomber][0].key == 0) && (keys[nomber][0].count == 0) && (keys[nomber][0].up_down == 0)) return; //Из массива keys оставшиеся строки в массив sequence_etalon_temp for (i = 0; i < max_pass_length; i++) { //Обходим строку массива keys if (keys[nomber][i].up_down == 1) { //Если нажатие ищем в массиве открытое нажатие этой же клавиши for (i1 = 0; i1 < PASSWORD; i1++) { //Обходим вспомогательный массив if ((ekp[i1].key == keys[nomber][i].key) && (ekp[i1].press_down != 0)/*иначе код 0 не обработается*/ && (ekp[i1].press_up == 0)) { //Если клавиша такая же и не закрытая flag = 1; //Если нашли такую же отбрасываем как повторную отсылку сигнала break; } } if (flag == 0) { //Если клавишу не нашли, добавляем как новую нажатую и заполняем начало межклавишного интервала for (i1 = 0; i1 < PASSWORD; i1++) { if ((ekp[i1].key == 0) && (ekp[i1].press_down == 0) && (ekp[i1].press_up == 0)) { ekp[i1].key = keys[nomber][i].key; ekp[i1].press_down = keys[nomber][i].count; if (i1 != 0) { //Если клавиша не первая заполняем предыдущий space ekp[i1-1].space = ekp[i1].press_down - ekp[i1-1].press_up; } break; } } } flag = 0; } else { //Если отжатие, ищем все открытые нажатия и закрываем, а также заканчиваем интервалы между нажатиями for (i1 = 0; i1 < PASSWORD; i1++) { if ((ekp[i1].key == keys[nomber][i].key) && (ekp[i1].press_down != 0) && (ekp[i1].press_up == 0)) { //Пишим время окончания удержания клавиши ekp[i1].press_up = keys[nomber][i].count; } } } } //Прочесываем последовательность еще раз и в press_down пишим время удержания клавиши for (i = 0; i < PASSWORD; i++) ekp[i1].press_down = ekp[i1].press_up - ekp[i1].press_down; //Переносим ekp в sequence_etalon_temp for (i = 0; i < PASSWORD; i++) { sequence_etalon_temp[nomber][i].key = ekp[i].key; sequence_etalon_temp[nomber][i].pressing = ekp[i].press_down; sequence_etalon_temp[nomber][i].space = ekp[i].space; } }; /////////////////////////////////////////////////////////////////////////////////// // Удаление шумов /////////////////////////////////////////////////////////////////////////////////// void delete_noise (void) { int i, i1; for (i = 0; i < REPEAT; i++) { for (i1 = 0; i1 < PASSWORD; i1++) { if (sequence_etalon_temp[i][i1].pressing > TIME_LIMIT) sequence_etalon_temp[i][i1].pressing = TIME_LIMIT; if (sequence_etalon_temp[i][i1].pressing < TIME_LIMIT*(-1)) sequence_etalon_temp[i][i1].pressing = TIME_LIMIT*(-1); if (sequence_etalon_temp[i][i1].space > TIME_LIMIT) sequence_etalon_temp[i][i1].space = TIME_LIMIT; if (sequence_etalon_temp[i][i1].space < TIME_LIMIT*(-1)) sequence_etalon_temp[i][i1].space = TIME_LIMIT*(-1); } } }; /////////////////////////////////////////////////////////////////////////////////// // Функции определения качества почерка /////////////////////////////////////////////////////////////////////////////////// //Функция расчета скорости нажатий int speed_press (int nomber) { int speed = 0; //Скорость long long int count = 0; //Счетчик нажатий long long int start_time; //Показания счетчика при первом нажатии int i = 0; //Счетчик if (keys[nomber][0].count == 0) return 0; else start_time = keys[nomber][0].count; for (i = 0; i < PASSWORD * 2; i++) { if (keys[nomber][i].count == 0) break; if (keys[nomber][i].up_down == 0) { //Подсчитываем колличество нажатий count++; } } //Рассчет скорости нажатий speed = 60000 / ((long long int)(keys[nomber][i-1].count - start_time) / count); return speed; //Возвращаем скорость нажатий (наж/мин) } //Функция расчета скорости ввода символов int speed_simbol (int nomber, int character_is_entered) { int speed = 0; //Скорость long long int start_time; //Показания счетчика при первом нажатии int i = 0; //Счетчик if (keys[nomber][0].count == 0) return 0; else start_time = keys[nomber][0].count; for (i = 0; i < PASSWORD * 2; i++) { if (keys[nomber][i].count == 0) break; } //Рассчет скорости нажатий speed = 60000 / ((long long int)(keys[nomber][i-1].count - start_time) / character_is_entered); return speed; //Возвращаем скорость ввода символов (симв/мин) } //Функция расчета процента ошибок char error_percent (int nomber, int character_is_entered) { char percent = 0; int error_press = 0; //колличество ошибок int i = 0; if (keys[nomber][0].count == 0) return 100; for (i = 0; i < PASSWORD * 2; i++) { if (keys[nomber][i].count == 0) break; if ((keys[nomber][i].key == 46) || (keys[nomber][i].key == 8)) error_press++; //46 - delete, 8 - backspace } //Рассчет скорости нажатий percent = (error_press * 100) / character_is_entered; return percent; //Процент ошибочних символов от всех символов } //Рассчет процента перекрытий char percent_of_overlaps (int nomber) { char percent = 0; long long int count = 0; //Счетчик нажатий long long int double_press = 0; //Колличество двойных нажатий и более char double_press_bool = 0; //Повторное нажатие есть или нет long long int lost_press = 0; //Предыдущее нажатие int i = 0; if (keys[nomber][0].count == 0) return 100; for (i = 0; i < PASSWORD * 2; i++) { if (keys[nomber][i].count == 0) break; if (keys[nomber][i].up_down == 0) { //Подсчитываем колличество нажатий count++; } //Подсчитываем число перекрытий if (keys[nomber][i].up_down == 1) double_press_bool ++; else double_press_bool --; if ((keys[nomber][i].up_down == 1) && (lost_press != keys[nomber][i].key) && (double_press_bool > 1)) double_press++; lost_press = keys[nomber][i].key; } //Рассчет скорости нажатий percent = (double_press / 100) * count; return percent; //Процент перекрытий от всех промежутков между символоми } //Рассчет процента аритмичности char unrhythmically (int nomber) { char un_rhythmically = 0; int speed [4] = {0,0,0,0}; //Скорости в четырех интервалах. int acceleration[3] = {0,0,0}; //Ускорение между 4 интервалами. int count = 0; //Коллличество нажатий long long int start_time; //Показания счетчика при первом нажатии int i = 0; //Счетчик if (keys[nomber][0].count == 0) return 0; for (i = 0; i < PASSWORD * 2; i++) { if (keys[nomber][i].count == 0) break; if (keys[nomber][i].up_down == 0) { //Подсчитываем колличество нажатий count++; } } count /= 4; //Считаем заново отсчитываем 4-ю часть символов и вычисляем скорость нажатий и т.д. int press = 0; //колличество отпусканий char quarter = 1; //какая четверть start_time = keys[nomber][0].count; for (i = 0; i < PASSWORD * 2; i++) { if (keys[nomber][i].count == 0) break; if (keys[nomber][i].up_down == 0) { press++; //Проверяем перешел в другую четверть или нет if (press > (count * quarter)) { //Вычисляем скорость для этой четверти speed[quarter-1] = 60000 / ((keys[nomber][i].count - start_time) / press); // Подготавливаемся к продолжению вычислений quarter++; start_time = keys[nomber][i].count; } } } //Посчитать процент изменения скорости между всеми интервалами. acceleration[0] = speed[0] > speed[1] ? speed[0]-speed[1] : speed[1]-speed[0]; acceleration[1] = speed[1] > speed[2] ? speed[1]-speed[2] : speed[2]-speed[1]; acceleration[2] = speed[3] > speed[2] ? speed[3]-speed[2] : speed[2]-speed[3]; if (speed[0] > speed[1]) speed[1] = speed[0]; if (speed[1] > speed[2]) speed[2] = speed[1]; if (speed[2] > speed[3]) speed[3] = speed[2]; //Посчитать среднеарифмитическое между предыдущими тремя значениями. un_rhythmically = ((acceleration[0] + acceleration[1] + acceleration[2]) / 3) * 100 / speed[3]; return un_rhythmically; //Процент аритмичности } //ОЦЕНКА подчерка по входным параметрам char estimation (int speed_press, int speed_simbol, char error_percent, char percent_of_overlaps, char unrhythmically) { char estimation = 2; char vector[5] = {0,0,0,0,0}; //Ставим оценку за скорость набора символов if (speed_simbol > 200) vector[0] = 5; else { if (speed_simbol > 150) vector[0] = 4; else { if (speed_simbol >= 100) vector[0] = 3; else vector[0] = 2; } } //Ставим оценку за ошибки if (error_percent < 2) vector[1] = 5; else { if (error_percent < 4) vector[1] = 4; else { if (error_percent <= 8) vector[1] = 3; else vector[1] = 2; } } //Ставим оценку за аритмичность if (unrhythmically < 10) vector[2] = 5; else { if (unrhythmically < 15) vector[2] = 4; else { if (unrhythmically <= 20) vector[2] = 3; else vector[2] = 2; } } // Оценка за число перекрытий if (percent_of_overlaps > 50) vector[3] = 5; else { if (percent_of_overlaps > 30) vector[3] = 4; else { if (percent_of_overlaps >= 10) vector[3] = 3; else vector[3] = 2; } } //Оценка за колличество нажатий if (speed_press > 210) vector[4] = 5; else { if (speed_press > 160) vector[4] = 4; else { if (speed_press >= 110) vector[4] = 3; else vector[4] = 2; } } //Подсчитываем сумму баллов estimation = vector[0] + vector[1] + vector[2] + vector[3] + vector[4]; return estimation; // Возвращаем оценку по 5 входным параметрам } //Определяем размер фразы int text_length (void) { int i; for (i = 0; i < PASSWORD; i++) { if (sequence_etalon[i].pressing == 0) break; } return i; } /////////////////////////////////////////////////////////////////////////////////// // Главная функция /////////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv[]) { //Заполняем массив //Первая строка keys[0][0].key = 64; keys[0][0].count = 0; keys[0][0].up_down = 1; keys[0][1].key = 75; keys[0][1].count = 50; keys[0][1].up_down = 1; keys[0][2].key = 64; keys[0][2].count = 70; keys[0][2].up_down = 0; keys[0][3].key = 75; keys[0][3].count = 170; keys[0][3].up_down = 0; keys[0][4].key = 74; keys[0][4].count = 250; keys[0][4].up_down = 1; keys[0][5].key = 74; keys[0][5].count = 350; keys[0][5].up_down = 0; //Вторая строка keys[1][0].key = 64; keys[1][0].count = 0; keys[1][0].up_down = 1; keys[1][1].key = 64; keys[1][1].count = 50; keys[1][1].up_down = 0; keys[1][2].key = 75; keys[1][2].count = 70; keys[1][2].up_down = 1; keys[1][3].key = 75; keys[1][3].count = 170; keys[1][3].up_down = 0; keys[1][4].key = 74; keys[1][4].count = 250; keys[1][4].up_down = 1; keys[1][5].key = 74; keys[1][5].count = 350; keys[1][5].up_down = 0; //Третья строка keys[2][0].key = 64; keys[2][0].count = 0; keys[2][0].up_down = 1; keys[2][1].key = 64; keys[2][1].count = 54; keys[2][1].up_down = 1; keys[2][2].key = 64; keys[2][2].count = 71; keys[2][2].up_down = 0; keys[2][3].key = 64; keys[2][3].count = 172; keys[2][3].up_down = 0; keys[2][4].key = 74; keys[2][4].count = 251; keys[2][4].up_down = 1; keys[2][5].key = 74; keys[2][5].count = 353; keys[2][5].up_down = 0; //На идентификацию data[0].key = 64; data[0].count = 0; data[0].up_down = 1; data[1].key = 64; data[1].count = 48; data[1].up_down = 0; data[2].key = 75; data[2].count = 68; data[2].up_down = 1; data[3].key = 75; data[3].count = 165; data[3].up_down = 0; data[4].key = 74; data[4].count = 251; data[4].up_down = 1; data[5].key = 74; data[5].count = 355; data[5].up_down = 0; //Считаем эталон int stability_kd = create_etalon (); //Проверяем идентификацию double measure = 30; //Мера Хемминга int stability = 20; //Стабильность float ident = identification (measure, stability); return EXIT_SUCCESS; };