Введение
В этом проекте вы научитесь создавать программу для практики набору текста на языке программирования C. Вы узнаете, как выполнять различные упражнения по набору, включая тренировки с одиночными строками, множественными строками и набором на основе раскладки клавиатуры. Эти программы помогут вам повысить скорость и точность набора текста.
👀 Предварительный просмотр
Start typing association exercises.
Please enter the hidden character indicated by '?'.
Press the space key to start.
AS?FG
?m,./\
67890-?\
?XCVB
zx?vb
!"?$%
ZXC?B
hjk?;:]
...(omit)...
🎯 Задачи
В рамках этого проекта вы научитесь:
- Создавать программу для практики набору текста на языке C.
- Реализовывать упражнения по набору одиночных строк, множественных строк и ассоциаций с раскладкой клавиатуры.
- Использовать библиотеку
cursesдля операций ввода и вывода на экран. - Перемешивать порядок вопросов для разнообразия в практике.
🏆 Достижения
После завершения этого проекта вы сможете:
- Создавать программу на языке C для имитации практики набору текста.
- Обрабатывать пользовательский ввод и проверять его правильность.
- Генерировать случайные вопросы и перемешивать их порядок.
- Использовать библиотеку
cursesдля продвинутых операций ввода и вывода на экран.
Проектная среда
Для проекта требуется использование библиотеки curses. Установите ее с помощью следующих команд:
sudo apt-get update
sudo apt-get install libncurses5-dev
Цель заголовочного файла getputch.h в коде - предоставить кроссплатформенную библиотеку функций ввода и вывода на экран, обеспечивающую правильную работу программы при выполнении операций ввода и вывода на экран в различных операционных системах и средах компилятора, особенно при обработке вывода символа новой строки.
Далее мы рассмотрим основные упражнения по набору текста, которые в основном включают в себя указатели, строковые массивы и циклические структуры в языке C.
Мы покажем применение строковых массивов, начиная от простого ввода одного символа до практики с множеством неупорядоченных слов.
Введите символ
Перейдите в каталог ~/project и создайте файл проекта typing1a.c:
cd ~/project
touch typing1a.c
Далее нам нужно написать код на языке C для создания программы для практики набору текста, которая позволяет вводить строку. Программа выглядит следующим образом:
#include <time.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "getputch.h"
int main(void)
{
int i;
char *str = "How do you do?"; /* The string to be input */
int len = strlen(str); /* Number of characters in the string */
init_getputch();
printf("Please type as shown.\n");
printf("%s\n", str); /* Display the string to be input */
fflush(stdout);
for (i = 0; i < len; i++) {
int ch;
do {
ch = getch(); /* Read input from the keyboard */
if (isprint(ch)) {
putch(ch); /* Display the pressed key */
if (ch!= str[i]) /* If a wrong key is pressed */
putch('\b'); /* Move the cursor back one space */
}
} while (ch!= str[i]);
}
term_getputch();
return 0;
}
Игроку требуется ввести строку, на которую указывает указатель str: How do you do?. Благодаря взаимозаменяемости указателей и массивов, символы 'H', 'o',..., '?' в строке могут быть последовательно представлены как str[0], str[1],..., str[13].
Кроме того, переменная len представляет длину строки str и имеет начальное значение 14. Функция strlen() используется для получения длины строки.
Цикл for увеличивает значение переменной i от 0, 1, 2,... в течение len итераций, чтобы последовательно пройти по символам в строке от начала до конца. Во время каждой итерации символ str[i] равен 'H', 'o',..., '?', то есть это символы, которые нужно ввести. Эта практика набора не принимает неверные символы (программа не перейдет к следующему символу, пока игрок не введет правильный символ). Это управление обеспечивается циклом do, внутри которого выполняются следующие действия:
- Вводимый символ (возвращаемое значение функции
getch) присваивается переменнойch. - Если символ
chявляется печатаемым символом, он отображается с помощью функцииputch(исключая неотображаемые символы, такие как новая строка и табуляция). - Если символ
chне равен символу, который нужно ввестиstr[i], выводится символ возврата на шаг назад'\b', чтобы переместить курсор на одну позицию назад. Это гарантирует, что следующий введенный символ будет отображен в той же позиции.
После выполнения вышеуказанных шагов вычисляется управляющее выражение цикла do (ch!= str[i]). Когда вводится неверный символ (когда ch не равен str[i]), цикл do запускается снова. В этот момент программа не переходит к следующему символу, а снова выполняет соответствующую часть в цикле do... while. После ввода правильного символа значение i увеличивается в цикле for, и программа переходит к следующему символу. После ввода всех символов программа отобразит время, затраченное игроком.
Скомпилируйте и запустите программу с помощью следующих команд:
cd ~/project
gcc -o typing1a typing1a.c -lcurses
./typing1a

Вы можете практиковаться несколько раз, чтобы повысить свою скорость. Если вам кажется скучным практиковаться с строкой How do you do?, вы также можете выбрать другую строку для практики.
Удаление введенных символов
Перейдите в каталог ~/project и создайте файл проекта typing1b.c:
cd ~/project
touch typing1b.c
Теперь давайте посмотрим на программу. Код выглядит следующим образом:
#include <time.h>
#include <stdio.h>
#include <string.h>
#include "getputch.h"
int main(void)
{
int i;
char *str = "How do you do?"; /* The string to be entered */
int len = strlen(str); /* The number of characters in the string str */
init_getputch();
printf("Please type as shown.\n");
for (i = 0; i < len; i++) {
/* Display the characters after str[i] and return the cursor to the beginning */
printf("%s \r", &str[i]);
fflush(stdout);
while (getch()!= str[i])
;
}
term_getputch();
return 0;
}
Эта программа немного отличается от предыдущей. Каждый раз, когда вводится правильный символ, один символ исчезает, а остальные символы сдвигаются вперед. Аналогично, программа не переходит к следующему символу, пока игрок не введет правильную клавишу. Когда игрок правильно вводит все символы, все символы исчезнут, и программа завершится.
Хотя операция, выполняемая здесь, более "продвинутая", чем в предыдущей программе, сама программа на самом деле короче. Тело оператора for состоит всего из двух коротких инструкций.
&str[i], переданное функцииprintfв инструкцииprintf("%s \r", &str[i]);, является указателем наstr[i]. Поскольку значение переменнойiравно0, указатель&str[i]будет указывать на символ'H', в результате чего на экране отобразится строкаHow do you do?, начиная сstr[0], как показано на рисунке выше. Затем программа выведет пробельные символы и возврат каретки\rсразу после этой строки и вернет курсор в позицию символа'H'в начале строки.- Если введенный символ (возвращаемое значение функции
getch) не равенstr[i], то есть введенный символ не'H', операторwhileбудет выполняться в цикле до тех пор, пока игрок не введет правильный символ, после чего операторwhileзавершится. - Затем значение переменной
iстанет равным1под влиянием оператораfor. Как показано на рисунке выше, инструкцияprintf("%s \r", &str[i]);выведет строкуow do you do?, начиная сstr[1], затем выведет пробельные символы и возврат каретки и вернет курсор в позицию символа'o'в начале. После этого, под действием последующего оператораwhile, программа будет ожидать, пока игрок правильно введет'o'.
Скомпилируйте и запустите программу с помощью следующих команд:
cd ~/project
gcc -o typing1b typing1b.c -lcurses
./typing1a

Ввод нескольких строк
Далее расширим предыдущую программу, чтобы игрок мог практиковать ввод нескольких строк.
Перейдите в каталог ~/project и создайте файл проекта с именем typing2a.c:
cd ~/project
touch typing2a.c
Теперь посмотрим на программу. Код выглядит следующим образом:
#include <time.h>
#include <stdio.h>
#include <string.h>
#include "getputch.h"
#define QNO 12 /* Number of questions */
int main(void)
{
char *str[QNO] = {"book", "computer", "default", "comfort",
"monday", "power", "light", "music",
"programming", "dog", "video", "include"};
int i, stage;
init_getputch();
printf("Start typing practice.\n");
printf("Press the spacebar to begin.\n");
while (getch()!= ' ') /* Wait until */
; /* the player presses the spacebar */
for (stage = 0; stage < QNO; stage++) {
int len = strlen(str[stage]); /* Number of characters in string str[stage] */
for (i = 0; i < len; i++) {
/* Display the characters after str[stage][i] and return the cursor to the beginning */
printf("%s \r", &str[stage][i]);
fflush(stdout);
while (getch()!= str[stage][i])
;
}
}
term_getputch();
return 0;
}
В этой программе после ввода одной строки следующая строка отображается на той же строке для ввода игроком. Всего доступно 12 строк для практики.
Эта программа в основном основана на предыдущей, но есть несколько отличий:
- Оператор
forвложен.
- Поскольку количество слов в вопросе изменилось с 1 на 12, добавлен внешний оператор
for. Этот операторforвыполняетQNOитераций, начиная с 0, для переменнойstage. Внутренний циклforпослеstrlen(str[stage])эквивалентен циклуforв предыдущей программе. - Строка для ввода на каждой итерации - это
str[stage](эквивалентноstrв предыдущей программе). Количество символов для ввода зависит от строки, поэтому операторstrlen(str[stage])вычисляет длину строкиstr[stage], используемой в вопросе, и сохраняет ее в переменнойlen.
- Символ для ввода теперь не
str[i], аstr[stage][i].
Внутри внутреннего цикла for символ для ввода - это str[stage][i], что эквивалентно str[i] в предыдущей программе.
Скомпилируйте и запустите программу с помощью следующих команд:
cd ~/project
gcc -o typing2a typing2a.c -lcurses
./typing2a

Перемешивание порядка вопросов (Метод 1)
После нескольких практических занятий с предыдущей программой следующая строка, которая появляется в вопросе, автоматически приходится в голову, что ослабляет эффект тренировки. Теперь давайте перемешаем порядок вопросов.
Перейдите в каталог ~/project и создайте файл проекта typing2b.c:
cd ~/project
touch typing2b.c
Теперь давайте посмотрим на программу. Код выглядит следующим образом:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getputch.h"
#define QNO 12 /* Number of questions */
#define swap(type, x, y) do { type t = x; x = y; y = t; } while (0)
int main(void)
{
char *str[QNO] = {"book", "computer", "default", "comfort",
"monday", "power", "light", "music",
"programming", "dog", "video", "include"};
int i, stage;
int qno[QNO]; /* Order of questions */
init_getputch();
srand(time(NULL)); /* Set the seed for random numbers */
for (i = 0; i < QNO; i++)
qno[i] = i;
for (i = QNO - 1; i > 0; i--) {
int j = rand() % (i + 1);
if (i!= j)
swap(int, qno[i], qno[j]);
}
printf("Start typing practice.\n");
printf("Press the spacebar to begin.\n");
while (getch()!= ' ') /* Wait until */
; /* the player presses the spacebar */
for (stage = 0; stage < QNO; stage++) {
int len = strlen(str[qno[stage]]); /* Number of characters in the string str[qno[stage]] */
for (i = 0; i < len; i++) {
/* Display the characters after str[qno[stage]][i] and return the cursor to the beginning */
printf("%s \r", &str[qno[stage]][i]);
fflush(stdout);
while (getch()!= str[qno[stage]][i])
;
}
}
term_getputch();
return 0;
}
Для перемешивания порядка вопросов программа вводит новый массив с именем qno с типом элементов int и размером QNO (который равен количеству строк в вопросах, то есть 12).
Перед началом практики по набору текста два первых цикла for используются для присвоения каждому элементу массива qno значений в порядке 0, 1, 2,..., 11.
Как и в предыдущей программе, все вхождения str[stage] были заменены на str[qno[stage]], так как в каждой итерации этой программы вопрос основан на str[qno[stage]].
- Когда
stageравно 0; так как значениеqno[0]равно 2, вопрос, показанный программой, будетstr[2], то естьdefault. - Когда
stageравно 1; так как значениеqno[1]равно 1, вопрос, показанный программой, будетstr[1], то естьcomputer.
И так далее. После практики с 12 строками программа завершится.
Скомпилируйте и запустите программу с помощью следующих команд:
cd ~/project
gcc -o typing2b typing2b.c -lcurses
./typing2b

Перемешивание порядка вопросов (Метод 2)
Следующая программа перемешивает порядок вопросов с использованием другого метода без применения массива. Эта программа требует меньшего количества переменных и более компактна по сравнению с предыдущей.
Перейдите в каталог ~/project и создайте файл проекта typing2c.c:
cd ~/project
touch typing2c.c
Теперь давайте посмотрим на программу. Код выглядит следующим образом:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getputch.h"
#define QNO 12 /* Number of Questions */
#define swap(type, x, y) do { type t = x; x = y; y = t; } while (0)
int main(void)
{
char *str[QNO] = {"book", "computer", "default", "comfort",
"monday", "power", "light", "music",
"programming", "dog", "video", "include"};
int i, stage;
init_getputch();
srand(time(NULL)); /* Set random seed */
for (i = QNO - 1; i > 0; i--) { /* Shuffle the array str */
int j = rand() % (i + 1);
if (i!= j)
swap(char *, str[i], str[j]);
}
printf("Start Typing Practice.\n");
printf("Press the spacebar to begin.\n");
while (getch()!= ' ') /* Wait until */
; /* the player presses the spacebar */
for (stage = 0; stage < QNO; stage++) {
int len = strlen(str[stage]); /* Number of characters in the string str[stage] */
for (i = 0; i < len; i++) {
/* Display the characters after str[stage][i] and return the cursor to the beginning */
printf("%s \r", &str[stage][i]);
fflush(stdout);
while (getch()!= str[stage][i])
;
}
}
term_getputch();
return 0;
}
Каждый элемент массива str указывает на строки book, computer, default,.... После обмена значениями str[0] и str[2], str[0] указывает на default, а str[2] указывает на book.
Первый цикл for в программе (вышеприведенный код) отвечает за перестановку указателей, которые являются значениями элементов массива str, тем самым перемешивая элементы. Поскольку объекты, которые обмениваются, являются указателями, первый аргумент, передаваемый в функцию-макрос swap, равен char *.
Во втором цикле for в основном теле программы каждый этап вопросов возвращается к str[stage] (что в листинге 8 - 4 было str[qno[stage]], что было более сложно). Это происходит потому, что массив str был случайным образом переупорядочен, и выводя str[0], str[1],..., str[QNO - 1] в порядке, получается случайный порядок вопросов.
Одна из недостатков этого метода заключается в том, что один раз перемешав порядок слов, его нельзя восстановить. Имейте это в виду.
Скомпилируйте и запустите программу с помощью следующих команд:
cd ~/project
gcc -o typing2c typing2c.c -lcurses
./typing2c

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


На раскладке клавиатуры, показанной на рисунке, даже если удерживать клавишу [Shift] при нажатии клавиши [0], никакой информация не будет введена.
Что касается раскладки этой клавиатуры, мы можем заметить следующее.
- Она состоит из 4 слоев клавиш.
- Каждый слой разделен на клавиши для левой руки и клавиши для правой руки, причем левая рука нажимает на черные клавиши, а правая - на синие.
- Есть клавиши, которые можно нажимать без удерживания клавиши
[Shift], и есть клавиши, которые требуют удерживания клавиши[Shift]при нажатии.
Мы называем различные наборы, классифицированные по слоям/рукам/нажатию клавиши [Shift], "блоками", и вся клавиатура состоит из 4 × 2 × 2 = 16 блоков в общей сложности.
Например, блок клавиш для левой руки с удерживанием клавиши [Shift] на 3-м слое - это [A], [S], [D], [F], [G] (обрабатываемые соответственно мизинцем, безымянным пальцем, средним пальцем, указательным пальцем и указательным пальцем).
В этой обучающей программе в качестве вопроса предлагается блок, но программа скрывает один символ в этом блоке с помощью знака "?". Например, для следующего вопроса игрок должен ассоциировать скрытый знак "?" с заглавной буквой D и затем ввести эту букву.
A S? F G
Код и результат выполнения
Перейдите в каталог ~/project и создайте файл проекта с именем typing3.c:
cd ~/project
touch typing3.c
Программа, написанная в соответствии с вышеуказанными рекомендациями, приведена ниже:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getputch.h"
#define NO 30 /* Number of exercises */
#define KTYPE 16 /* Number of blocks */
int main(void)
{
char *kstr[] = {"12345", "67890-^\\", /* Layer 1 */
"!\"#$%", "&'() =~|", /* Layer 1 [Shift] */
"qwert", "yuiop@[", /* Layer 2 */
"QWERT", "YUIOP`{", /* Layer 2 [Shift] */
"asdfg", "hjkl;:]", /* Layer 3 */
"ASDFG", "HJKL+*}", /* Layer 3 [Shift] */
"zxcvb", "nm,./\\", /* Layer 4 */
"ZXCVB", "NM<> _", /* Layer 4 [Shift] */
};
int i, stage;
clock_t start, end; /* Start and end times */
init_getputch();
srand(time(NULL)); /* Set the seed for random number generation */
printf("Start typing association exercises.\n");
printf("Please enter the hidden character indicated by '?'.\n");
printf("Press the space key to start.\n");
fflush(stdout);
while (getch()!= ' ')
;
start = clock(); /* Start time */
for (stage = 0; stage < NO; stage++) {
int k, p, key;
char temp[10];
do {
k = rand() % KTYPE;
p = rand() % strlen(kstr[k]);
key = kstr[k][p];
} while (key == ' ');
strcpy(temp, kstr[k]);
temp[p] = '?';
printf("%s", temp);
fflush(stdout);
while (getch()!= key)
;
putchar('\n');
}
end = clock(); /* End time */
printf("Time taken: %.1f seconds.\n", (double)(end - start) / CLOCKS_PER_SEC);
term_getputch();
return 0;
}
Макрос KTYPE представляет количество блоков, которое равно 16, а массив kstr используется для хранения строк, состоящих из символов каждого блока, расположенных слева направо.
С точки зрения цели обучения, вопрос не будет содержать символ ?, поэтому последняя строка для объявленного блока - это NM<> _, а не NM<>?_ (поскольку программа не использует пробел для генерации вопросов, это не вызовет ошибки).
Если раскладка вашей клавиатуры отличается от той, которая показана в этом примере, пожалуйста, соответствующим образом измените объявление массива kstr.
Первый цикл do while отвечает за генерацию вопроса.
- Переменная
kуказывает, из какого блока нужно сгенерировать вопрос. Поскольку это значение соответствует индексу массиваkstr, оно задается как случайное число, большее или равное 0 и меньшееKTYPE.Поскольку количество блоков
KTYPEравно 16, сгенерированное случайное число будет в диапазоне от 0 до 15. - Переменная
pуказывает, какой символ внутри блока должен быть скрыт для генерации вопроса. Поскольку это значение соответствует индексу строки, используемой для генерации вопроса внутри блока, оно задается как случайное число, большее или равное 0 и меньшее количества символов внутри блока.Предположим, что
kравно 0, блок состоит из 5 символов,'12345', поэтомуpзадается как случайное число в диапазоне от 0 до 4. Кроме того, еслиkравно 3, блок состоит из 8 символов,'&'()=~|', поэтомуpзадается как случайное число в диапазоне от 0 до 7. - Переменная
keyпредставляет скрытый символ.
Например, если k равно 0 и p равно 2, символ '3' в блоке '12345' является key. Поскольку программа уже присвоила пробельный символ '' символам, которые не должны использоваться для генерации вопросов, цикл do-while используется для повторной генерации вопроса, если скрытый символ key является пробельным символом.
Далее функция strcpy копирует kstr[k] в temp и присваивает '?' temp[p]. Это генерирует строку 12?45, которая будет отображена на экране.
Если программа может отобразить строку temp и прочитать символ key, введенный с клавиатуры, это правильно. Как и предыдущие программы для практики набора текста, эта программа не принимает неправильно введенные символы. После 30 тренировочных раундов программа завершит выполнение.
Скомпилируйте и запустите программу с помощью следующих команд:
cd ~/project
gcc -o typing3 typing3.c -lcurses
./typing3
Start typing association exercises.
Please enter the hidden character indicated by '?'.
Press the space key to start.
AS?FG
?m,./\
67890-?\
?XCVB
zx?vb
!"?$%
ZXC?B
hjk?;:]
…(omit)…
Резюме
В этом проекте вы научились создавать программу для практики набора текста на языке программирования C. Эта программа для практики набора текста предоставляет пользователям гибкую интерактивную платформу для улучшения навыков набора текста, будь то для программирования или обычного общения. Она представляет собой ценный инструмент для повышения скорости и точности набора текста.



