Загрузка данных
import asyncio, re, edge_tts
WORDS = {
"include": "инклуд", "define": "дефайн",
"iostream": "айострим", "cstring": "цэ стринг", "cstdio": "цэ стдио",
"using": "юзинг", "namespace": "неймспейс", "std": "эс тэ дэ",
"int": "инт", "float": "флоат", "double": "дабл", "char": "чар",
"bool": "бул", "void": "войд", "true": "тру", "false": "фолс",
"main": "мейн", "cin": "си ин", "cout": "си аут", "endl": "энд эл",
"return": "ретерн", "if": "иф", "else": "элс", "switch": "свитч",
"case": "кейс", "break": "брейк", "default": "дефолт",
"for": "фор", "while": "вайл", "do": "ду", "continue": "континью",
"strlen": "эс тэ эр лен", "strcat": "эс тэ эр кат",
"new": "нью", "delete": "делит", "struct": "стракт",
"FILE": "ФАЙЛ заглавными буквами", "fopen": "эф опен",
"fprintf": "эф принт эф", "fwrite": "эф райт", "fclose": "эф клоуз",
"sizeof": "сайз оф", "MULT": "МУЛЬТ заглавными буквами",
"User": "Юзер с большой буквы", "show": "шоу", "func": "фанк",
"arr": "арр", "len": "лен", "id": "айди", "code": "код",
"rate": "рейт", "res": "рез",
"a": "а", "b": "бэ", "c": "цэ", "d": "дэ", "e": "е", "f": "эф",
"i": "и", "j": "джей", "m": "эм", "p": "пэ", "pp": "пэ пэ",
"s": "эс", "u": "у", "u1": "у один", "x": "икс", "y": "игрек",
"f1": "эф один", "f2": "эф два"
}
LITS = {
"'A'": "одиночная кавычка открывается, заглавная А, одиночная кавычка закрывается",
'" "': "кавычки открываются, пробел, кавычки закрываются",
'"\\t"': "кавычки открываются, обратный слэш тэ, кавычки закрываются",
'"Yes"': "кавычки открываются, Йес, кавычки закрываются",
'"No"': "кавычки открываются, Ноу, кавычки закрываются",
'"One"': "кавычки открываются, Уан, кавычки закрываются",
'"Five"': "кавычки открываются, Файв, кавычки закрываются",
'"Other"': "кавычки открываются, Азер, кавычки закрываются",
'"Hello "': "кавычки открываются, Хеллоу пробел, кавычки закрываются",
'"Ivanov"': "кавычки открываются, твоя фамилия латиницей, кавычки закрываются",
'"a.txt"': "кавычки открываются, а точька тэ икс тэ, кавычки закрываются",
'"w"': "кавычки открываются, дабл-ю, кавычки закрываются",
'"Text"': "кавычки открываются, Текст, кавычки закрываются",
'"b.bin"': "кавычки открываются, бэ точька бин, кавычки закрываются",
'"wb"': "кавычки открываются, дабл-ю бэ, кавычки закрываются",
}
OPS = {
"<<": "две угловые скобки влево", ">>": "две угловые скобки вправо",
"<=": "меньше или равно", ">=": "больше или равно",
"==": "двойное равно", "!=": "не равно",
"&&": "два амперсанда", "||": "две вертикальные черты",
"++": "плюс плюс", "--": "минус минус", "**": "две звездочки",
"(": "круглая скобка открывается", ")": "круглая скобка закрывается",
"{": "фигурная скобка открывается", "}": "фигурная скобка закрывается",
"[": "квадратная скобка открывается", "]": "квадратная скобка закрывается",
";": "точька с запятой", ":": "двоеточие", ",": "запятая",
".": "точька", "=": "равно", "+": "плюс", "-": "минус",
"*": "звездочка", "&": "амперсанд", "#": "решетка"
}
def code_to_speech(line, num):
line_clean = line.replace("1, 2, 3, 4, 5, 6, 7, 8, 9, 10", "ARRAY10")
is_inc = line_clean.startswith("#include")
tokens = re.findall(r'"[^"]*"|\'[^\']*\'|\d+\.\d+|<<|>>|<=|>=|==|!=|&&|\|\||\+\+|--|\*\*|[A-Za-z_]\w*|\d+|[^\s]', line_clean)
out = []
prev_word = False
for idx, t in enumerate(tokens):
is_w = bool(re.match(r'^[A-Za-z0-9_]+$', t))
if prev_word and (is_w or (t in ("*", "&") and idx > 0 and tokens[idx-1] in ("int", "double", "char", "User", "FILE"))):
out.append("пробел")
elif idx > 0 and tokens[idx-1] == "]" and is_w:
out.append("пробел")
if t == "ARRAY10":
out.append("числа от 1 до 10 через запятую")
elif t in LITS:
out.append(LITS[t])
elif re.match(r'^\d+\.\d+$', t):
a, b = t.split(".")
out.append(f"{a}, точька, {b}")
elif t in ("<", ">"):
if is_inc:
out.append("угловая скобка открывается" if t == "<" else "угловая скобка закрывается")
else:
out.append("знак меньше" if t == "<" else "знак больше")
elif t in OPS:
out.append(OPS[t])
elif t in WORDS:
out.append(WORDS[t])
else:
out.append(t)
prev_word = is_w
return f"Строка {num}: " + ", ".join(out) + "."
RAW = """
Билет номер 1. Вопрос 1.
Предложение 1: Переменная — это именованная область оперативной памяти, которая хранит данные определенного типа и позволяет изменять их значение во время работы программы.
Предложение 2: Основные типы данных в Си плюс плюс: инт хранит целые числа и занимает 4 байта, флоат хранит дробные числа одинарной точности и занимает 4 байта, дабл хранит дробные числа двойной точности и занимает 8 байт.
Предложение 3: Тип чар хранит один символ по таблице аски и занимает 1 байт, а логический тип бул занимает 1 байт и хранит значение истины тру или лжи фолс.
Предложение 4: Для чтения данных с клавиатуры используется поток ввода си ин с оператором вправо, а для вывода на экран — поток си аут с оператором влево из библиотеки айострим.
Пишем полный код к билету 1.
CODE: #include <iostream>
CODE: using namespace std;
CODE: int main() {
CODE: int a = 5;
CODE: float b = 2.5;
CODE: double c = 3.14;
CODE: char d = 'A';
CODE: bool e = true;
CODE: cin >> a >> b >> c >> d >> e;
CODE: cout << a << " " << b << " " << c << " " << d << " " << e;
CODE: return 0;
CODE: }
Билет номер 2. Вопрос 2.
Предложение 1: Логические операции применяются к логическим выражениям для проверки сложных условий и всегда возвращают результат тру или фолс.
Предложение 2: Виды логических операций: два амперсанда — это логическое И, которое истинно только когда оба условия истинны; две вертикальные черты — это логическое ИЛИ, которое истинно, если истинно хотя бы одно условие; восклицательный знак — это логическое НЕ, которое меняет значение условия на противоположное.
Предложение 3: Условные операторы нужны для ветвления программы: оператор иф элс выполняет разные блоки кода в зависимости от истинности условия, а оператор свитч кейс выбирает одну из нескольких веток по целочисленному значению переменной.
Пишем полный код к билету 2.
CODE: #include <iostream>
CODE: using namespace std;
CODE: int main() {
CODE: int x = 5;
CODE: if (x > 0 && x < 10) {
CODE: cout << "Yes";
CODE: } else {
CODE: cout << "No";
CODE: }
CODE: switch (x) {
CODE: case 1: cout << "One"; break;
CODE: case 5: cout << "Five"; break;
CODE: default: cout << "Other"; break;
CODE: }
CODE: return 0;
CODE: }
Билет номер 3. Вопрос 3.
Предложение 1: Циклы предназначены для многократного выполнения одного и того же блока кода до тех пор, пока условие продолжения цикла остается истинным.
Предложение 2: В Си плюс плюс есть три вида циклов: цикл со счетчиком фор используется, когда заранее известно число повторений; цикл с предусловием вайл проверяет условие до выполнения тела и может не выполниться ни разу; цикл с постусловием ду вайл проверяет условие после тела и гарантированно выполняется минимум один раз.
Предложение 3: Оператор брейк используется для немедленного досрочного выхода из всего цикла, а оператор континью пропускает оставшуюся часть текущей итерации и сразу переходит к следующей итерации цикла.
Пишем полный код к билету 3.
CODE: #include <iostream>
CODE: using namespace std;
CODE: int main() {
CODE: for (int i = 0; i < 5; i++) {
CODE: if (i == 2) continue;
CODE: cout << i << " ";
CODE: }
CODE: int j = 0;
CODE: while (j < 5) {
CODE: if (j == 3) break;
CODE: j++;
CODE: }
CODE: do {
CODE: j--;
CODE: } while (j > 0);
CODE: return 0;
CODE: }
Билет номер 4. Вопрос 4.
Предложение 1: Массив — это структура данных фиксированного размера, состоящая из упорядоченного набора элементов одного типа, которые хранятся в оперативной памяти непрерывно друг за другом.
Предложение 2: Обращение к элементам массива происходит по целочисленному индексу в квадратных скобках, причем нумерация элементов всегда начинается с нуля.
Пишем полный код к билету 4.
CODE: #include <iostream>
CODE: using namespace std;
CODE: int main() {
CODE: int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
CODE: for (int i = 0; i < 10; i++) {
CODE: cout << arr[i] << " ";
CODE: }
CODE: return 0;
CODE: }
Билет номер 5. Вопрос 5.
Предложение 1: Двумерный массив — это массив, элементами которого являются одномерные массивы одинаковой длины, что позволяет представлять данные в виде таблицы со строками и столбцами.
Предложение 2: В оперативной памяти элементы двумерного массива располагаются одним непрерывным линейным блоком построчно: сначала подряд лежат все элементы нулевой строки, сразу за ними элементы первой строки и так далее.
Пишем полный код к билету 5.
CODE: #include <iostream>
CODE: using namespace std;
CODE: int main() {
CODE: int m[3][2] = {{1, 2}, {3, 4}, {5, 6}};
CODE: for (int i = 0; i < 3; i++) {
CODE: for (int j = 0; j < 2; j++) {
CODE: cout << m[i][j] << "\t";
CODE: }
CODE: cout << endl;
CODE: }
CODE: return 0;
CODE: }
Билет номер 6. Вопрос 6.
Предложение 1: Нуль-терминированная строка — это символьный массив типа чар, в конце которого обязательно находится служебный нулевой символ обратный слэш ноль с кодом ноль, обозначающий конец текста.
Предложение 2: Функции из библиотеки цэ стринг: функция эс тэ эр лен вычисляет количество символов в строке без учета завершающего нуля, а функция эс тэ эр цэ эм пэ посимвольно сравнивает две строки и возвращает ноль при их полном совпадении.
Предложение 3: Функция эс тэ эр копи копирует содержимое второй строки в первую вместе с нулевым символом, а функция эс тэ эр кат выполняет конкатенацию, то есть дописывает вторую строку в конец первой.
Пишем полный код к билету 6.
CODE: #include <iostream>
CODE: #include <cstring>
CODE: using namespace std;
CODE: int main() {
CODE: char s[50] = "Hello ";
CODE: int len = strlen(s);
CODE: strcat(s, "Ivanov");
CODE: cout << len << " " << s;
CODE: return 0;
CODE: }
Билет номер 7. Вопрос 7.
Предложение 1: Указатель — это специальная переменная, значением которой является адрес ячейки оперативной памяти, где хранится другая переменная.
Предложение 2: Опасность неинициализированных указателей в том, что они содержат случайный адрес в памяти, и попытка чтения или записи по такому адресу приводит к повреждению чужих данных или аварийному завершению программы.
Предложение 3: Операция взятия адреса обозначается знаком амперсанда и возвращает адрес переменной в памяти, а операция разыменования обозначается звездочкой и дает прямой доступ к значению, лежащему по адресу в указателе.
Предложение 4: Двойной указатель объявляется с двумя звездочками и представляет собой указатель, который хранит адрес другого указателя.
Пишем полный код к билету 7.
CODE: #include <iostream>
CODE: using namespace std;
CODE: int main() {
CODE: int x = 10;
CODE: int *p = &x;
CODE: *p = 20;
CODE: int **pp = &p;
CODE: **pp = 30;
CODE: cout << x;
CODE: return 0;
CODE: }
Билет номер 8. Вопрос 8.
Предложение 1: Подпрограмма — это именованный блок кода для многократного вызова: функция вычисляет и возвращает результат с помощью оператора ретерн, а процедура имеет тип войд и только выполняет действия без возврата значения.
Предложение 2: Существует три способа передачи параметров: при передаче по значению создается локальная копия и исходная переменная не меняется; при передаче по ссылке через амперсанд передается псевдоним оригинала; при передаче по указателю через звездочку передается адрес переменной в памяти.
Предложение 3: Рекурсивная функция — это функция, которая вызывает саму себя внутри своего тела, и в ней обязательно должно быть базовое условие выхода, иначе возникнет бесконечная рекурсия и переполнение стека вызовов.
Пишем полный код к билету 8.
CODE: #include <iostream>
CODE: using namespace std;
CODE: double func(bool f, int &a, double *b) {
CODE: if (f) return a + *b;
CODE: else return a - *b;
CODE: }
CODE: int main() {
CODE: int x = 10;
CODE: double y = 2.5;
CODE: cout << func(true, x, &y);
CODE: return 0;
CODE: }
Билет номер 9. Вопрос 9.
Предложение 1: Статический массив выделяется на стеке и его размер должен быть константой, известной на этапе компиляции, а динамический массив создается в куче прямо во время работы программы.
Предложение 2: Преимущества динамических массивов в том, что их размер можно задавать через переменную с клавиатуры, объем кучи значительно больше стека, а выделенную память можно освободить в любой момент, когда массив больше не нужен.
Предложение 3: Оператор нью в Си плюс плюс сам вычисляет размер типа данных, возвращает типизированный указатель и вызывает конструкторы объектов, а функция маллок из языка Си принимает размер в байтах, возвращает нетипизированный указатель войд со звездочкой и не вызывает конструкторы.
Пишем полный код к билету 9.
CODE: #include <iostream>
CODE: using namespace std;
CODE: int main() {
CODE: double *a = new double[10];
CODE: for (int i = 0; i < 10; i++) {
CODE: cin >> a[i];
CODE: }
CODE: delete[] a;
CODE: return 0;
CODE: }
Билет номер 10. Вопрос 10.
Предложение 1: Главное отличие динамического двумерного массива от массива фиксированного размера состоит в том, что статический массив лежит в памяти одним сплошным блоком, а динамический представляет собой массив указателей, где каждый элемент указывает на отдельную строку, выделенную в разных участках кучи.
Предложение 2: Память под динамический двумерный массив выделяется в два этапа: сначала создается массив указателей на строки, а затем в цикле выделяется память под каждую строку; освобождение памяти через делит происходит строго в обратном порядке.
Пишем полный код к билету 10.
CODE: #include <iostream>
CODE: using namespace std;
CODE: int main() {
CODE: int **a = new int*[7];
CODE: for (int i = 0; i < 7; i++) {
CODE: a[i] = new int[9];
CODE: }
CODE: for (int i = 0; i < 7; i++) {
CODE: for (int j = 0; j < 9; j++) {
CODE: cin >> a[i][j];
CODE: }
CODE: }
CODE: for (int i = 0; i < 7; i++) {
CODE: delete[] a[i];
CODE: }
CODE: delete[] a;
CODE: return 0;
CODE: }
Билет номер 11. Вопрос 11.
Предложение 1: Структура — это пользовательский составной тип данных, создаваемый ключевым словом стракт, который позволяет объединить несколько переменных различных типов, называемых полями, под одним общим именем.
Предложение 2: Назначение структур заключается в удобной группировке логически связанных характеристик одного сложного объекта, например карточки студента, товара или книги, для передачи и обработки их как единого целого.
Пишем полный код к билету 11.
CODE: #include <iostream>
CODE: using namespace std;
CODE: struct User {
CODE: int id;
CODE: char code;
CODE: double rate;
CODE: };
CODE: void show(User &u) {
CODE: cout << u.id << " " << u.code << " " << u.rate;
CODE: }
CODE: int main() {
CODE: User u1 = {1, 'A', 5.5};
CODE: show(u1);
CODE: return 0;
CODE: }
Билет номер 12. Вопрос 12.
Предложение 1: Файлы делятся на два вида: в текстовых файлах все данные преобразуются и хранятся в виде последовательностей символов, а в бинарных файлах данные записываются на диск побайтово в том же внутреннем двоичном виде, в каком они лежат в оперативной памяти.
Предложение 2: Функция эф опен открывает файл в нужном режиме чтения или записи и возвращает указатель на поток ФАЙЛ, а функция эф клоуз сохраняет буферы на диск и закрывает файл.
Предложение 3: Функции эф принт эф и эф скан эф предназначены для форматированной записи и чтения данных в текстовых файлах, а функции эф райт и эф рид записывают и считывают блоки сырых байтов заданного размера в бинарных файлах.
Пишем полный код к билету 12.
CODE: #include <cstdio>
CODE: int main() {
CODE: FILE *f1 = fopen("a.txt", "w");
CODE: fprintf(f1, "Text");
CODE: fclose(f1);
CODE: int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
CODE: FILE *f2 = fopen("b.bin", "wb");
CODE: fwrite(arr, sizeof(int), 10, f2);
CODE: fclose(f2);
CODE: return 0;
CODE: }
Билет номер 13. Вопрос 13.
Предложение 1: Процесс сборки программы из исходного кода состоит из четырех этапов: сначала препроцессор обрабатывает директивы с решеткой, затем компилятор переводит код Си плюс плюс в код ассемблера, после чего ассемблер создает машинный объектный файл, а компоновщик объединяет объектные файлы и библиотеки в готовый исполняемый файл.
Предложение 2: Заголовочные файлы с расширением точька аш используются для хранения объявлений функций, структур и констант, чтобы подключать их в разные модули программы без дублирования кода.
Предложение 3: Препроцессор изменяет исходный текст программы до начала компиляции: директива инклуд вставляет содержимое другого файла, директива дефайн создает константу или макрос для текстовой подстановки, а директива андеф отменяет действие ранее объявленного дефайн.
Предложение 4: Макрос — это инструкция препроцессора для автоматической замены текста с параметрами до компиляции, причем все аргументы макроса берутся в круглые скобки, чтобы не нарушался порядок математических операций.
Пишем полный код к билету 13.
CODE: #include <iostream>
CODE: #define MULT(a, b) ((a) * (b))
CODE: using namespace std;
CODE: int main() {
CODE: int res = MULT(2 + 3, 4);
CODE: cout << res;
CODE: return 0;
CODE: }
"""
# Автосклейка строк, если мессенджер разрезал сообщение
items = []
for raw_line in RAW.strip().splitlines():
s = raw_line.strip()
if not s:
continue
if s.startswith(("Билет ", "Предложение ", "Пишем ", "CODE:")):
items.append(s)
else:
items[-1] += " " + s
tickets_audio = []
current_audio = ""
txt_lines = []
code_line_num = 0
for item in items:
if item.startswith("Билет "):
if current_audio:
tickets_audio.append(current_audio)
current_audio = f"{item} ... ... "
txt_lines.append(f"\n==================== {item} ====================")
code_line_num = 0
elif item.startswith("Пишем "):
current_audio += f"{item} ... ... "
txt_lines.append(f"\n--- {item} ---")
code_line_num = 0
elif item.startswith("CODE:"):
code_line_num += 1
cpp_line = item[5:].strip()
spoken_audio = code_to_speech(cpp_line, code_line_num)
spoken_txt = spoken_audio.replace("точька", "точка")
txt_lines.append(f"{code_line_num}: {cpp_line}")
txt_lines.append(f" Диктовка: {spoken_txt}")
current_audio += f"{spoken_audio} ... ... Повторяю: {spoken_audio} ... ... ... "
else:
clean_txt = item.replace("точька", "точка")
txt_lines.append(f"{clean_txt}\nПовторяю: {clean_txt}")
current_audio += f"{item} ... ... Повторяю: {item} ... ... ... "
if current_audio:
tickets_audio.append(current_audio)
with open("bilet_text.txt", "w", encoding="utf-8") as f:
f.write("\n".join(txt_lines))
print("Текстовый файл bilet_text.txt со всеми полными кодами и ответами сохранен!")
async def main():
out_file = "full_exam_with_code.mp3"
open(out_file, "wb").close() # очищаем файл перед записью
for idx, t_audio in enumerate(tickets_audio, 1):
for attempt in range(5):
try:
comm = edge_tts.Communicate(t_audio, voice="ru-RU-DmitryNeural", rate="-25%")
with open(out_file, "ab") as f:
async for chunk in comm.stream():
if chunk["type"] == "audio":
f.write(chunk["data"])
print(f"Озвучен и добавлен Билет {idx} из {len(tickets_audio)}...")
break
except Exception as e:
print(f"Повтор подключения для Билета {idx} (попытка {attempt+1}/5)...")
await asyncio.sleep(2)
print(f"Готово! Полный аудиофайл сохранен в {out_file}")
asyncio.run(main())