diff --git a/tests/cpp/integration/oop_mid1_correct.cpp b/tests/cpp/integration/oop_mid1_correct.cpp new file mode 100644 index 0000000..ec6c23e --- /dev/null +++ b/tests/cpp/integration/oop_mid1_correct.cpp @@ -0,0 +1,67 @@ +#include +#include + +class User { +private: + static int nextId; + static int usersCount; + + const int id; + std::string username; + +public: + User(const std::string& username) : id(nextId), username(username) { + ++nextId; + ++usersCount; + } + + ~User() { + --usersCount; + } + + static int getUsersCount() { + return usersCount; + } + + int getId() const { + return id; + } + + std::string getName() const { + return username; + } + + void setName(const std::string& newName) { + username = newName; + } +}; + +int User::nextId = 1; +int User::usersCount = 0; + +int main() { + std::cout << User::getUsersCount() << std::endl; + + User alice("Alice"); + User bob("Bob"); + User charlie("Charlie"); + + std::cout << User::getUsersCount() << std::endl; + + std::cout << alice.getId() << std::endl; + std::cout << bob.getId() << std::endl; + std::cout << charlie.getId() << std::endl; + + charlie.setName("Charles"); + + std::cout << charlie.getName() << std::endl; + + { + User bobCopy("Bob"); + std::cout << User::getUsersCount() << std::endl; + } + + std::cout << User::getUsersCount() << std::endl; + + return 0; +} \ No newline at end of file diff --git a/tests/cpp/integration/oop_mid1_incorrect.cpp b/tests/cpp/integration/oop_mid1_incorrect.cpp new file mode 100644 index 0000000..2fddbc9 --- /dev/null +++ b/tests/cpp/integration/oop_mid1_incorrect.cpp @@ -0,0 +1,63 @@ +#include +#include + +class User { +private: + static int nextId; + static int usersCount; + + const int id; + std::string username; + +public: + User(const std::string& username) : id(nextId++), username(username) { + ++usersCount; + } + + static int getUsersCount() { + return usersCount; + } + + int getId() const { + return id; + } + + std::string getName() const { + return username; + } + + void setName(const std::string& newName) { + username = newName; + } +}; + +int User::nextId = 1; +int User::usersCount = 0; + + +int main() { + std::cout << User::getUsersCount() << std::endl; + + User alice("Alice"); + User bob("Bob"); + User charlie("Charlie"); + + std::cout << User::getUsersCount() << std::endl; + + std::cout << alice.getId() << std::endl; + std::cout << bob.getId() << std::endl; + std::cout << charlie.getId() << std::endl; + + charlie.setName("Charles"); + + std::cout << charlie.getName() << std::endl; + + { + User bobCopy("Bob"); + std::cout << User::getUsersCount() << std::endl; + } + + std::cout << User::getUsersCount() << std::endl; + + return 0; +} \ No newline at end of file diff --git a/tests/cpp/integration/oop_mid2_correct.cpp b/tests/cpp/integration/oop_mid2_correct.cpp new file mode 100644 index 0000000..b71388f --- /dev/null +++ b/tests/cpp/integration/oop_mid2_correct.cpp @@ -0,0 +1,62 @@ +#include +#include +#include + +class Fraction { +private: + int numerator; + int denominator; + + void simplify() { + int gcd = std::gcd(numerator, denominator); + numerator /= gcd; + denominator /= gcd; + + if (denominator < 0) { + numerator = -numerator; + denominator = -denominator; + } + } + +public: + Fraction(int num, int den) : numerator(num), denominator(den) { + if (denominator == 0) { + throw std::invalid_argument("Denominator cannot be zero"); + } + simplify(); + } + + Fraction operator*(const Fraction& other) const { + return Fraction(numerator * other.numerator, denominator * other.denominator); + } + + Fraction operator+(const Fraction& other) const { + return Fraction(numerator * other.denominator + other.numerator * denominator, + denominator * other.denominator); + } + + friend std::ostream& operator<<(std::ostream& os, const Fraction& f) { + os << f.numerator << "/" << f.denominator; + return os; + } +}; + + +int main() { + Fraction f1(1, 2); + Fraction f2(3, 4); + + Fraction sum = f1 + f2; + Fraction product = f1 * f2; + + std::cout << sum << std::endl; + std::cout << product << std::endl; + + Fraction f3(2, 4); + std::cout << f3 << std::endl; + + Fraction f4(3, -6); + std::cout << f4 << std::endl; + + return 0; +} diff --git a/tests/cpp/integration/oop_mid2_incorrect.cpp b/tests/cpp/integration/oop_mid2_incorrect.cpp new file mode 100644 index 0000000..c959e43 --- /dev/null +++ b/tests/cpp/integration/oop_mid2_incorrect.cpp @@ -0,0 +1,60 @@ +#include +#include +#include + +class Fraction { +private: + int numerator; + int denominator; + + void simplify() { + int gcd = std::gcd(numerator, denominator); + numerator /= gcd; + denominator /= gcd; + + if (denominator < 0) { + denominator = -denominator; + } + } + +public: + Fraction(int num, int den) : numerator(num), denominator(den) { + if (denominator == 0) { + throw std::invalid_argument("Denominator cannot be zero"); + } + simplify(); + } + + Fraction operator*(const Fraction& other) const { + return Fraction(numerator * other.numerator, denominator * other.denominator); + } + + Fraction operator+(const Fraction& other) const { + return Fraction(numerator * other.denominator + other.numerator * denominator, + denominator * other.denominator); + } + + friend std::ostream& operator<<(std::ostream& os, const Fraction& f) { + os << f.numerator << "/" << f.denominator; + return os; + } +}; + +int main() { + Fraction f1(1, 2); + Fraction f2(3, 4); + + Fraction sum = f1 + f2; + Fraction product = f1 * f2; + + std::cout << sum << std::endl; + std::cout << product << std::endl; + + Fraction f3(2, 4); + std::cout << f3 << std::endl; + + Fraction f4(3, -6); + std::cout << f4 << std::endl; + + return 0; +} \ No newline at end of file diff --git a/workshop/main.py b/workshop/main.py index c35643f..914f1de 100644 --- a/workshop/main.py +++ b/workshop/main.py @@ -1,63 +1,50 @@ -import argparse -import sys -import inspect -from src import c_course, cpp_course -import os - - - -def init_task(task: c_course.BaseTaskClass): - print(task.init_task()) - - -def check_task(task: c_course.BaseTaskClass, solfile: str, name: str): - passed, msg = task.check() - print("Passed:", passed) - print(msg) - if passed: - sys.exit(0) - - sys.exit(1) - - -def dry_run_task(task: c_course.BaseTaskClass): - task.generate_task() - task._generate_tests() - for i, test in enumerate(task.tests): - print(f"TEST #{i + 1}:\n\t{test}") - sys.exit(1) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(required=True) - - course_modules = [ - c_course, - importlib.import_module("src.c++_course"), - ] - cli_parsers = [] - for course_module in course_modules: - cli_parsers.extend( - cli_parser - for _, cli_parser in inspect.getmembers(course_module, lambda obj: isinstance(obj, c_course.CLIParser)) - ) - - for cli_parser in cli_parsers: - task_parser = subparsers.add_parser(cli_parser.name) - cli_parser.add_cli_args(task_parser) - - # Регистратор для cpp задачек - for cli_parser in cpp_course.PARSERS: - task_parser = subparsers.add_parser(cli_parser.name) - cli_parser.add_cli_args(task_parser) - - args = parser.parse_args() - task = args.func(args) - match args.mode: - case "init": - init_task(task) - case "check": - check_task(task) - case "dry-run": - dry_run_task(task) +import argparse +import sys +from src import c_course, cpp_course + + + +def init_task(task: c_course.BaseTaskClass): + print(task.init_task()) + + +def check_task(task: c_course.BaseTaskClass): + passed, msg = task.check() + print("Passed:", passed) + print(msg) + if passed: + sys.exit(0) + + sys.exit(1) + + +def dry_run_task(task: c_course.BaseTaskClass): + task.generate_task() + task._generate_tests() + for i, test in enumerate(task.tests): + print(f"TEST #{i + 1}:\n\t{test}") + sys.exit(1) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers(required=True) + + for cli_parser in c_course.PARSERS: + task_parser = subparsers.add_parser(cli_parser.name) + cli_parser.add_cli_args(task_parser) + + # Регистратор для cpp задачек + for cli_parser in cpp_course.PARSERS: + task_parser = subparsers.add_parser(cli_parser.name) + cli_parser.add_cli_args(task_parser) + + args = parser.parse_args() + task = args.func(args) + match args.mode: + case "init": + init_task(task) + case "check": + check_task(task) + case "dry-run": + dry_run_task(task) \ No newline at end of file diff --git a/workshop/src/cpp_course/oop_mid1/__init__.py b/workshop/src/cpp_course/oop_mid1/__init__.py new file mode 100644 index 0000000..13bc8ce --- /dev/null +++ b/workshop/src/cpp_course/oop_mid1/__init__.py @@ -0,0 +1,2 @@ +from .oop_mid1_test import OopMid1Test +from .oop_mid1_cli import oop_mid_1_parser diff --git a/workshop/src/cpp_course/oop_mid1/oop_mid1_cli.py b/workshop/src/cpp_course/oop_mid1/oop_mid1_cli.py new file mode 100644 index 0000000..630158c --- /dev/null +++ b/workshop/src/cpp_course/oop_mid1/oop_mid1_cli.py @@ -0,0 +1,18 @@ +from ...base_module.base_cli import add_common_cli_args, get_common_cli_args, CLIParser +from .oop_mid1_test import OopMid1Test + + +def add_cli_args_oop_mid_1(parser): + add_common_cli_args(parser) + parser.set_defaults(func=create_task_oop_mid_1) + + +def create_task_oop_mid_1(args): + common_args = get_common_cli_args(args) + return OopMid1Test(**common_args) + + +oop_mid_1_parser = CLIParser( + name='oop_mid1', + add_cli_args=add_cli_args_oop_mid_1 +) \ No newline at end of file diff --git a/workshop/src/cpp_course/oop_mid1/oop_mid1_test.py b/workshop/src/cpp_course/oop_mid1/oop_mid1_test.py new file mode 100644 index 0000000..e91ae0c --- /dev/null +++ b/workshop/src/cpp_course/oop_mid1/oop_mid1_test.py @@ -0,0 +1,48 @@ +from ...base_module import BaseTaskClass, TestItem + + +class OopMid1Test(BaseTaskClass): + """OOP -- Mid_Task_1""" + + def __init__(self, seed: int = 42, **kwargs): + super().__init__( + compile_name="program", + seed=seed, + **kwargs + ) + + def generate_task(self) -> str: + return ( + "Реализуйте класс User для системы регистрации, который автоматически присваивает уникальные ID " + "каждому новому пользователю и подсчитывает их общее количество, используя статические члены.\n\n" + "1) Приватные статические поля\n" + "- static int nextId - хранит ID для следующего пользователя (изначально 1).\n" + "- static int usersCount - хранит текущее количество активных пользователей.\n\n" + "2) Поля объекта\n" + "- const int id - уникальный номер (задается в конструкторе и не меняется).\n" + "- std::string username.\n\n" + "3) Конструктор\n" + "- Принимает имя пользователя.\n" + "- Присваивает полю id значение nextId.\n" + "- Инкрементирует nextId.\n" + "- Инкрементирует usersCount.\n\n" + "4) Деструктор\n" + "- Декрементирует usersCount (уменьшает счетчик активных пользователей при удалении объекта).\n\n" + "5) Статический метод getUsersCount()\n" + "- Возвращает текущее количество пользователей.\n\n" + "6) Методы доступа\n" + "- getId() - возвращает ID.\n" + "- getName() - возвращает имя.\n\n" + "7) Методы изменения\n" + "- setName(const std::string& newName) — устанавливает новое имя пользователя." + ) + + def _generate_tests(self): + self.tests = [ + TestItem( + input_str="", + showed_input="no input", + expected="0\n3\n1\n2\n3\nCharles\n4\n3", + compare_func=lambda x, y: x.strip() == y.strip() + ) + ] \ No newline at end of file diff --git a/workshop/src/cpp_course/oop_mid2/__init__.py b/workshop/src/cpp_course/oop_mid2/__init__.py new file mode 100644 index 0000000..eed3e61 --- /dev/null +++ b/workshop/src/cpp_course/oop_mid2/__init__.py @@ -0,0 +1,2 @@ +from .oop_mid2_test import OopMid2Test +from .oop_mid2_cli import oop_mid_2_parser diff --git a/workshop/src/cpp_course/oop_mid2/oop_mid2_cli.py b/workshop/src/cpp_course/oop_mid2/oop_mid2_cli.py new file mode 100644 index 0000000..487c792 --- /dev/null +++ b/workshop/src/cpp_course/oop_mid2/oop_mid2_cli.py @@ -0,0 +1,19 @@ +from ...base_module.base_cli import add_common_cli_args, get_common_cli_args, CLIParser +from .oop_mid2_test import OopMid2Test + + +def add_cli_args_oop_mid_2(parser): + add_common_cli_args(parser) + parser.set_defaults(func=create_task_oop_mid_2) + + +def create_task_oop_mid_2(args): + common_args = get_common_cli_args(args) + return OopMid2Test(**common_args) + + +oop_mid_2_parser = CLIParser( + name='oop_mid2', + add_cli_args=add_cli_args_oop_mid_2 +) + diff --git a/workshop/src/cpp_course/oop_mid2/oop_mid2_test.py b/workshop/src/cpp_course/oop_mid2/oop_mid2_test.py new file mode 100644 index 0000000..d7ee34c --- /dev/null +++ b/workshop/src/cpp_course/oop_mid2/oop_mid2_test.py @@ -0,0 +1,47 @@ +from ...base_module import BaseTaskClass, TestItem + + +class OopMid2Test(BaseTaskClass): + """OOP -- Mid_Task_2""" + + def __init__(self, seed: int = 42, **kwargs): + super().__init__( + compile_name="program", + seed=seed, + **kwargs + ) + + def generate_task(self) -> str: + return ( + "Реализуйте класс Fraction, представляющий обыкновенную дробь (числитель и знаменатель). " + "Класс должен всегда хранить дробь в несократимом виде (например, 2/4 должно храниться как 1/2).\n\n" + "1) Приватные поля\n" + "- int numerator (числитель)\n" + "- int denominator (знаменатель)\n\n" + "2) Приватный метод simplify()\n" + "- Использует std::gcd (наибольший общий делитель) из заголовка для сокращения дроби.\n" + "- Вызывается в конструкторе и после каждой арифметической операции.\n" + "- Следит за знаком: если знаменатель отрицательный, минус переносится в числитель.\n\n" + "3) Конструктор\n" + "- Принимает числитель и знаменатель.\n" + "- Если знаменатель равен 0, выбрасывает исключение std::invalid_argument.\n\n" + "4) Оператор * (умножение)\n" + "- Перегрузка умножения одной дроби на другую.\n" + "- Возвращает новый объект Fraction.\n\n" + "5) Оператор + (сложение)\n" + "- Перегрузка сложения двух дробей.\n" + "- Находит общий знаменатель, складывает и возвращает новый результат (автоматически сокращенный благодаря simplify).\n\n" + "6) Оператор << (вывод)\n" + "- Дружественная функция для вывода в поток в формате num/denom." + ) + + def _generate_tests(self): + self.tests = [ + TestItem( + input_str="", + showed_input="no input", + expected="5/4\n3/8\n1/2\n-1/2", + compare_func=lambda x, y: x.strip() == y.strip() + ) + ] +