From dbd1dfe45dfe83452fabe8337fbe9b923c099372 Mon Sep 17 00:00:00 2001 From: Artem Darius Weber Date: Mon, 30 Dec 2024 12:47:48 +0300 Subject: [PATCH] feat: add BinarySearchTree class and integrate birth_date handling in Student class LAB 3 TASK 4 --- lab2/binary_search_tree.rb | 46 ++++++++++++++++++++++++++++++++++++++ lab2/main.rb | 45 ++++++++++++++++++++++++++++++------- lab2/output_students.txt | 0 lab2/student.rb | 16 ++++++++----- 4 files changed, 93 insertions(+), 14 deletions(-) create mode 100644 lab2/binary_search_tree.rb create mode 100644 lab2/output_students.txt diff --git a/lab2/binary_search_tree.rb b/lab2/binary_search_tree.rb new file mode 100644 index 0000000..8fb86bc --- /dev/null +++ b/lab2/binary_search_tree.rb @@ -0,0 +1,46 @@ +class BinarySearchTree + include Enumerable + + class Node + attr_accessor :student, :left, :right + + def initialize(student) + @student = student + @left = nil + @right = nil + end + end + + def initialize + @root = nil + end + + def add(student) + @root = insert(@root, student) + end + + def each(&block) + in_order_traversal(@root, &block) + end + + private + + def insert(node, student) + return Node.new(student) if node.nil? + + if student.birth_date < node.student.birth_date + node.left = insert(node.left, student) + else + node.right = insert(node.right, student) + end + node + end + + def in_order_traversal(node, &block) + return if node.nil? + + in_order_traversal(node.left, &block) + yield node.student + in_order_traversal(node.right, &block) + end +end diff --git a/lab2/main.rb b/lab2/main.rb index d439c1f..44796f1 100644 --- a/lab2/main.rb +++ b/lab2/main.rb @@ -1,8 +1,10 @@ +require 'date' require_relative 'contact' require_relative 'person' require_relative 'student' require_relative 'student_short' require_relative 'student_repository' +require_relative 'binary_search_tree' def test_classes contact = Contact.new(phone: '+798912465', telegram: '@example_user', email: 'test@example.com') @@ -11,38 +13,34 @@ def test_classes person = Person.new(id: '1', git: 'https://github.com/example', contact: contact) puts "Person Contact Info: #{person.contact_info}" - student = Student.new( id: '2', git: 'https://github.com/student_example', contact: contact, surname: 'Иванов', name: 'Иван', - patronymic: 'Иванович' + patronymic: 'Иванович', + birth_date: Date.new(2000, 5, 15) ) puts "Student Full Info: #{student.to_s}" puts "Student Initials: #{student.surname_and_initials}" puts "Student Contact Info: #{student.contact_info}" - student_short = StudentShort.from_student(student) puts "Student Short Info: #{student_short.to_s}" - file_path = 'students.txt' students = StudentRepository.read_from_txt(file_path) puts "Read Students from File:" students.each { |s| puts s.to_s } - output_path = 'output_students.txt' StudentRepository.write_to_txt(output_path, students) puts "Students written to file: #{output_path}" end - def test_parsing - student_string = 'Иванов Иван Иванович | ID: 3 | Phone: +79876543210 | Telegram: @ivan_user | Email: ivan@example.com | Git: https://github.com/ivanov' + student_string = 'Иванов Иван Иванович | ID: 3 | Phone: +79876543210 | Telegram: @ivan_user | Email: ivan@example.com | Git: https://github.com/ivanov | Birth Date: 2001-01-01' student = Student.from_string(student_string) puts "Parsed Student: #{student.to_s}" @@ -51,6 +49,34 @@ def test_parsing puts "Parsed StudentShort: #{student_short.to_s}" end +def test_binary_search_tree + bst = BinarySearchTree.new + + student1 = Student.new( + id: '1', + git: 'https://github.com/student1', + contact: Contact.new(phone: '+123456789', telegram: '@student1', email: 'student1@example.com'), + surname: 'Смирнов', + name: 'Алексей', + patronymic: 'Иванович', + birth_date: Date.new(1999, 2, 15) + ) + student2 = Student.new( + id: '2', + git: 'https://github.com/student2', + contact: Contact.new(phone: '+987654321', telegram: '@student2', email: 'student2@example.com'), + surname: 'Иванов', + name: 'Иван', + patronymic: 'Сергеевич', + birth_date: Date.new(2001, 5, 10) + ) + + bst.add(student1) + bst.add(student2) + + puts "Students in BST (sorted by birth_date):" + bst.each { |student| puts student.to_s } +end if __FILE__ == $0 puts "=== Testing Classes ===" @@ -58,4 +84,7 @@ if __FILE__ == $0 puts "\n=== Testing Parsing ===" test_parsing -end + + puts "\n=== Testing Binary Search Tree ===" + test_binary_search_tree +end \ No newline at end of file diff --git a/lab2/output_students.txt b/lab2/output_students.txt new file mode 100644 index 0000000..e69de29 diff --git a/lab2/student.rb b/lab2/student.rb index c9b1145..3902575 100644 --- a/lab2/student.rb +++ b/lab2/student.rb @@ -2,22 +2,23 @@ require_relative 'person' require_relative 'contact' class Student < Person - attr_accessor :surname, :name, :patronymic + attr_accessor :surname, :name, :patronymic, :birth_date NAME_REGEX = /\A[А-Яа-яЁёA-Za-z\-]+\z/ - def initialize(id:, git:, contact:, surname:, name:, patronymic:) + def initialize(id:, git:, contact:, surname:, name:, patronymic:, birth_date:) super(id: id, git: git, contact: contact) @surname = surname @name = name @patronymic = patronymic + @birth_date = birth_date validate_student end def self.from_string(student_string) parts = student_string.split('|').map(&:strip) - raise ArgumentError, 'Invalid student string format' if parts.size < 6 + raise ArgumentError, 'Invalid student string format' if parts.size < 7 name_parts = parts[0].split(' ') raise ArgumentError, 'Invalid name format' if name_parts.size != 3 @@ -28,6 +29,7 @@ class Student < Person telegram = parts[3].split(': ').last email = parts[4].split(': ').last git = parts[5].split(': ').last + birth_date = Date.parse(parts[6].split(': ').last) contact = Contact.new(phone: phone, telegram: telegram, email: email) @@ -37,7 +39,8 @@ class Student < Person contact: contact, surname: surname, name: name, - patronymic: patronymic + patronymic: patronymic, + birth_date: birth_date ) end @@ -48,11 +51,11 @@ class Student < Person def to_s "#{@surname} #{@name} #{@patronymic} | ID: #{@id} | " \ "Phone: #{@contact.phone || 'N/A'} | Telegram: #{@contact.telegram || 'N/A'} | " \ - "Email: #{@contact.email || 'N/A'} | Git: #{@git}" + "Email: #{@contact.email || 'N/A'} | Git: #{@git} | Birth Date: #{@birth_date}" end def get_info - "#{surname_and_initials}, Git: #{@git}, Contact: #{contact_info}" + "#{surname_and_initials}, Git: #{@git}, Contact: #{contact_info}, Birth Date: #{@birth_date}" end private @@ -61,6 +64,7 @@ class Student < Person raise ArgumentError, 'Surname is required' if @surname.nil? || @surname.strip.empty? raise ArgumentError, 'Name is required' if @name.nil? || @name.strip.empty? raise ArgumentError, 'Patronymic is required' if @patronymic.nil? || @patronymic.strip.empty? + raise ArgumentError, 'Birth date is required' if @birth_date.nil? raise ArgumentError, "Invalid surname format: #{@surname}" unless valid_name?(@surname) raise ArgumentError, "Invalid name format: #{@name}" unless valid_name?(@name)