Предизвикателства > Осмодекемврийско пътуване


Осмодекемврийско пътуване
Краен срок: 07.12.2023 18:00
Точки: 1

В навечерието на 8 декември доста от вас са заети да организират грандиозно пътуване до курорти като Банско, където с колеги ще се насладите на [Шкембе Чорба](/student/69), струваща колкото половин семестриална такса. Неразделна част от пътуването е разпределението на цялата тайфа по коли. Още по-неразделна част от това начинание са задължителните претенции на пътуващите: - Някой не иска да се пуши в колата, за да не рискува здравето си, което по принцип така или иначе ще подложи на всевъзможни предизвикателства още при пристигането си. Друг настоява да се пуши, защото "нерви, брат". - Някой не иска да слуша чалга по пътя, но друг е убеден, че без да завърти "Константин - Студентка" поне брой пъти, съвпадащ с число от редицата на Фибоначи, което е равно на сумата от квадратите на две прости числа, няма да успее да изпие достатъчно алкохол, че да се забавли. - На някои колежки студената атмосфера в по-старите модели коли не им харесва, тъй като поради дългото планинско спускане изстиват и не могат да произведат достатъчно топлина, за да им се оросят крайниците (колежките, не автомобилите). Други колеги пък се надяват точно на това в колата да е студ, за да стоплят колежка в прегръдките си. ...ех размечтахме се за нашите студентски години! #### Задачата Напишете callable `organize` (може да е функция, може да е callable инстанция на клас... каквото можете, стига да е callable). `organize` ще приема два позиционни аргумента, които ние подаваме: - `list` от обекти от тип кола; - `list` от обекти от тип студент. Самите обекти кола и студент не ви интересуват. Вашата цел е да "настаните" всеки студент в една кола, така че всички да са доволни. Ако това е възможно, връщате `True`. Ако не е, връщате `False`. След като се изпълни вашият callable, ако резултатът е `True`, се очаква студентите да са настанени по колите (как настаняваме по колите пише по-долу). Ако резултатът е `False`, не ни интересува дали има настанени студенти, или всички коли са празни. Ясно е, че няма как да настаните всички, така че е все едно какво е състоянието на обектите. За да разберете дали дадена конфигурация от коли/студенти е валидна, т.е. ще върнете `True`, използвате следните публични методи на кола/студент (приемете, че `car` и `student` са примерни инстанции на класовете, които споменахме, че ще подаваме като вход в `list`-овете. - `car.add_student` - метод на класа кола, който очаква един позиционен аргумент от тип студент и го добавя в колата. Една кола побира само 4 пътници. За ваше улеснение, ако колата е пълна и се опитате са добавите студент, ще бъде възбуден `EnvironmentError`. - `car.remove_student` - метод на класа кола, който очаква един позиционен аргумент от тип студент и го маха от колата. Ако въпросният студент не е в колата (макар че викането на този метод зависи изцяло от вас, така че не би следвало, да стигате до там), ще се възбуди същото изключение. - `student.is_comfy` - метод на класа студент, който не очаква аргументи и връща булева стойност (`True`/`False`) в зависимост от това дали студентът се чувства комфортно в колата, в която се намира. Ако студентът все още не е в кола, методът връща `None`. За да проверите дали двама студенти са доволни от това да са в една и съща кола, единственият начин е да ги сложите в една кола и да проверите дали са доволни с метода `is_comfy`. Например, единият настоява да слуша чалга, а другият настоява да няма чалга. Имайте предвид, че студенти могат да са доволни в една кола, но недоволни в друга. Например, ако те настояват да им е топло, но в колата е студено. # EDIT Понеже питахте за пример, а идва празник, ето дефиниция на класовете, с които ще тестваме. ``` class Named: """Assign a name to instances of child classes.""" _instances = {} def __new__(cls, *args, **kwargs): """Store numbers isntances and assign names based on it.""" instance = super().__new__(cls) cls._instances[cls] = cls._instances.setdefault(cls, 0) + 1 instance.name = f'{cls.__name__} {cls._instances[cls]}' return instance class Car(Named): """A car for the task.""" CAPACITY = 4 def __init__(self, cold=None): """Initializator.""" self.cold = cold self.students = set() def add_student(self, student): """Add a student to a car and set the current car in student's fields.""" if len(self.students) == self.CAPACITY: raise EnvironmentError('Car is full') print(f'Putting {student} in {self}') self.students.add(student) student.set_car(self) def remove_student(self, student): """Remove a student from a car and unset the current car in student's fields.""" if student not in self.students: raise EnvironmentError('Student is not in the car.') print(f'Removing {student} from {self}') self.students.remove(student) student.unset_car() def __repr__(self): """Pretty print.""" return self.name class Student(Named): """Student for the task.""" def __init__(self, smoke=None, chalga=None, cold=None): """Initializator.""" self.smoke = smoke self.chalga = chalga self.cold = cold self.car = None def set_car(self, car): """Set a car for this student.""" self.car = car def unset_car(self): """Unset a car for this student.""" self.car = None def is_comfy(self): """Check if student is comfy in their current car.""" if self.car is None: return None if self.car.cold and self.cold is False: return False for student in self.car.students: if student is self: continue if student.smoke and self.smoke is False: return False if student.chalga and self.chalga is False: return False return True def __repr__(self): """Pretty print.""" return self.name ```
 1import unittest
 2
 3from solution import *
 4
 5
 6class TestSanity(unittest.TestCase):
 7    """Sanity test for organize."""
 8
 9    def test_sanity(self):
10        """Ensure name exists and is callable.."""
11        self.assertTrue(callable(organize))
12
13
14if __name__ == '__main__':
15    unittest.main()
 1import unittest
 2
 3# Thanks to this guy we need to prevent hacking. -> https://py-fmi.org/student/75
 4anti_rusalov_false = unittest.TestCase.assertFalse
 5anti_rusalov_true = unittest.TestCase.assertTrue
 6anti_rusalov_is = unittest.TestCase.assertIs
 7
 8from solution import *
 9
10from helpers import Car, Student
11
12
13class TesFull(unittest.TestCase):
14    """Full test for organize."""
15
16    def setUp(self):
17        """Setup for all test cases."""
18        Car._instances = {}
19        # Getting deep into a student's private internals.
20        # Do you feel it?
21        Student._instances = {} 
22
23    def test_empty(self):
24        """Test with empty cars."""
25        students = [Student(smoke=True, chalga=False, cold=None)]
26        for _ in range(20): # Anti Rusalov mechanism against random True/False returns
27            anti_rusalov_false(self, organize([], students))
28
29    def test_real_case_false(self):
30        """Test a real case for False."""
31        cars = [Car(cold=False)]
32        students = [Student(smoke=True, chalga=False, cold=None),
33                    Student(smoke=False, chalga=True, cold=None),]
34        # Can't put a smoker and nonsmoker together
35        for _ in range(20): # Anti Rusalov mechanism against random True/False returns
36            anti_rusalov_false(self, organize(cars, students))
37
38    def test_regular_case(self):
39        """Test a regular case."""
40        # https://www.youtube.com/watch?v=5PsnxDQvQpw
41        cars = [Car(cold=False), Car(cold=True)]
42        students = [Student(smoke=True, chalga=False, cold=None),
43                    Student(smoke=None, chalga=None, cold=None),
44                    Student(smoke=None, chalga=None, cold=None),
45                    Student(smoke=None, chalga=None, cold=None),
46                    Student(smoke=False, chalga=None, cold=False)]
47        anti_rusalov_true(self, organize(cars, students))
48        anti_rusalov_true(self, all([x.is_comfy() is True for x in students]))
49        # Last student is cold so can only go to first car
50        anti_rusalov_is(self, students[4].car, cars[0])
51        # The one above in the first car doesn't smoke so this one must be in car 2
52        anti_rusalov_is(self, students[0].car, cars[1])
53
54    def test_single_solution_case(self):
55        """Test a single-solution case."""
56        cars = [Car(cold=False), Car(cold=True)]
57        students = [Student(smoke=True, chalga=False, cold=False),
58                    Student(smoke=None, chalga=False, cold=None),
59                    Student(smoke=None, chalga=False, cold=None),
60                    Student(smoke=None, chalga=False, cold=None),
61                    Student(smoke=False, chalga=True, cold=None),
62                    Student(smoke=False, chalga=None, cold=None),
63                    Student(smoke=False, chalga=None, cold=None),
64                    Student(smoke=False, chalga=None, cold=None)]
65        anti_rusalov_true(self, organize(cars, students))
66        anti_rusalov_true(self, all([x.is_comfy() is True for x in students]))
67        # There is only one valid solution to this case
68        anti_rusalov_is(self, students[0].car, cars[0])
69        anti_rusalov_is(self, students[1].car, cars[0])
70        anti_rusalov_is(self, students[2].car, cars[0])
71        anti_rusalov_is(self, students[3].car, cars[0])
72        anti_rusalov_is(self, students[4].car, cars[1])
73        anti_rusalov_is(self, students[5].car, cars[1])
74        anti_rusalov_is(self, students[6].car, cars[1])
75        anti_rusalov_is(self, students[7].car, cars[1])
76
77    def test_big_input(self):
78        """Test a big case to ensure no huge bruteforcing."""
79        cars = [Car(cold=False), Car(cold=False), Car(cold=False), Car(cold=True)]
80        students = [Student(smoke=True, chalga=None, cold=None),
81                    Student(smoke=True, chalga=None, cold=None),
82                    Student(smoke=True, chalga=None, cold=None),
83                    Student(smoke=True, chalga=None, cold=None),
84                    Student(smoke=None, chalga=True, cold=None),
85                    Student(smoke=None, chalga=True, cold=None),
86                    Student(smoke=None, chalga=True, cold=None),
87                    Student(smoke=None, chalga=True, cold=None),
88                    Student(smoke=None, chalga=None, cold=True),
89                    Student(smoke=None, chalga=None, cold=True)]
90        anti_rusalov_true(self, organize(cars, students))
91        anti_rusalov_true(self, all([x.is_comfy() is True for x in students]))
92
93
94if __name__ == '__main__':
95    unittest.main()
Дискусия
Георги Кунчев
07.12.2023 16:21

Да, има и непретенциозни хора.
Мирослав Стояновски
07.12.2023 16:13

Възможно ли е даден студент да няма отношение по някой от критериите, тоест да е възможно да е comfy хем в кола с чалга, хем в кола без чалга ?
Георги Кунчев
06.12.2023 21:39

Освен да ти дам пример `organize(cars, students)`, не знам какво повече бих могъл, без да дефинирам коли и студенти. Ок, идва празник, борите се за една точка, халал да ви е. Добавям дефиницията на колите и студентите горе в условието.
Добромир Пеев
06.12.2023 20:56

Може ли примери
Георги Кунчев
06.12.2023 16:38

На сървъра ни има само built-in пакети, така че не.
Дария Лазарова
06.12.2023 16:03

Можем ли да използваме допълнителни пакети като more_itertools?
Георги Кунчев
06.12.2023 15:29

2 секунди за всички тестове. Осъзнавам, че ако ви изсипем огромна колекция това може да не е достатъчно, затова няма да го правим. ПП: Най-голямият ни тест е 10 студента с 4 коли.
Михаил Цанков
06.12.2023 15:25

Имат ли таймаут тестовете? Тоест колко бързо трябва да е решението ни
Георги Кунчев
05.12.2023 23:39

Да. Стига всички студенти да имат кола, всичко е точно.
Мартин Кузманов
05.12.2023 23:33

А може ли кола да остане празна?