← Computer Programming II

Variant 1: Student Course Tracker

A university needs a system to manage student course enrollments. The system should log every enrollment action, validate course codes, compute GPA, and support creating students from registration strings.

  1. Write a decorator log_action(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should print "[ACTION] {func.__name__} executed", call the original function with the same arguments, and return its result.
  2. Create a class Student with:
    • __init__(self, name, student_id) — stores the student’s name, student ID, and initializes an empty dictionary _courses (course_code → grade as an integer).
    • A class variable _total_students starting at 0, incremented in __init__ each time a new student is created.
    • An instance method enroll(self, course_code, grade) decorated with @log_action — converts course_code to uppercase, then adds it to _courses with the given grade. Returns the string "{name} enrolled in {course_code} with grade {grade}".
    • An instance method gpa(self) — computes and returns the average of all grades in _courses, rounded to 1 decimal place. If no courses exist, returns 0.0.
    • An instance method best_course(self) — returns the course code with the highest grade. If no courses exist, returns "No courses".
    • A class method from_registration(cls, data) — takes a string in the format "Name-ID" (e.g., "Dilshod-2612345"), splits it, and returns a new Student object.
    • A static method is_valid_id(student_id) — returns True if the student ID is exactly 7 characters long and all characters are digits, False otherwise.
    • A class method total_students(cls) — returns _total_students.

Input

s1 = Student("Aziza", "2601001")
s1.enroll("math101", 85)
s1.enroll("phys201", 92)
s1.enroll("eng102", 78)

s2 = Student.from_registration("Jasur-2601002")
s2.enroll("CS101", 95)
s2.enroll("math101", 88)

print(f"{s1.name}: GPA = {s1.gpa()}, Best = {s1.best_course()}")
print(f"{s2.name}: GPA = {s2.gpa()}, Best = {s2.best_course()}")

print(f"Valid ID '2601001': {Student.is_valid_id('2601001')}")
print(f"Valid ID '26A': {Student.is_valid_id('26A')}")
print(f"Total students: {Student.total_students()}")

Expected Output

[ACTION] enroll executed
[ACTION] enroll executed
[ACTION] enroll executed
[ACTION] enroll executed
[ACTION] enroll executed
Aziza: GPA = 85.0, Best = PHYS201
Jasur: GPA = 91.5, Best = CS101
Valid ID '2601001': True
Valid ID '26A': False
Total students: 2

Variant 2: Product Inventory System

A warehouse needs a system to manage product inventory. The system should log stock changes, validate product codes, compute total inventory value, and support creating products from catalog strings.

  1. Write a decorator track_change(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should call the original function with the same arguments, capture its return value, print "[STOCK] {return_value}", and return the result.
  2. Create a class Product with:
    • __init__(self, name, price, quantity) — stores the product name, price (float), and quantity (int).
    • A class variable _all_products — an empty list that collects every Product instance created (append self in __init__).
    • An instance method restock(self, amount) decorated with @track_change — adds amount to quantity and returns the string "{name}: added {amount}, now {quantity}".
    • An instance method sell(self, amount) decorated with @track_change — if amount is greater than quantity, returns the string "Not enough {name} in stock" without changing quantity. Otherwise, subtracts amount from quantity and returns "{name}: sold {amount}, now {quantity}".
    • An instance method total_value(self) — returns price * quantity rounded to 2 decimal places.
    • A class method from_catalog(cls, entry) — takes a string in the format "Name:Price:Quantity" (e.g., "Laptop:999.99:10"), parses it, converts price to float and quantity to int, and returns a new Product.
    • A static method is_valid_code(code) — returns True if code starts with "PRD-" and the rest are digits (e.g., "PRD-001"), False otherwise.
    • A class method warehouse_value(cls) — returns the sum of total_value() for all products in _all_products, rounded to 2 decimal places.

Input

p1 = Product("Keyboard", 45.50, 20)
p2 = Product.from_catalog("Monitor:299.99:5")

p1.restock(10)
p1.sell(25)
p1.sell(50)
p2.sell(2)

print(f"{p1.name}: value = ${p1.total_value()}")
print(f"{p2.name}: value = ${p2.total_value()}")

print(f"Valid code 'PRD-001': {Product.is_valid_code('PRD-001')}")
print(f"Valid code 'ABC-123': {Product.is_valid_code('ABC-123')}")
print(f"Warehouse total: ${Product.warehouse_value()}")

Expected Output

[STOCK] Keyboard: added 10, now 30
[STOCK] Keyboard: sold 25, now 5
[STOCK] Not enough Keyboard in stock
[STOCK] Monitor: sold 2, now 3
Keyboard: value = $227.5
Monitor: value = $899.97
Valid code 'PRD-001': True
Valid code 'ABC-123': False
Warehouse total: $1127.47

Variant 3: Library Book Manager

A library needs a system to manage book borrowing. The system should log borrow and return actions, validate ISBNs, compute availability, and support creating books from catalog entries.

  1. Write a decorator log_operation(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should call the original function with the same arguments, capture its return value. If the return value is True, print "[OK] {func.__name__} successful". If False, print "[FAIL] {func.__name__} denied". Return the result.
  2. Create a class Book with:
    • __init__(self, title, total_copies) — stores the title, total number of copies (int), initializes _borrowed to 0, and appends self to the class variable _library.
    • A class variable _library — an empty list that collects every Book instance created.
    • An instance method borrow(self) decorated with @log_operation — if _borrowed is already equal to total_copies, returns False. Otherwise, increments _borrowed by 1 and returns True.
    • An instance method return_book(self) decorated with @log_operation — if _borrowed is 0, returns False. Otherwise, decrements _borrowed by 1 and returns True.
    • An instance method available(self) — returns total_copies - _borrowed.
    • An instance method usage_percent(self) — returns the percentage of copies currently borrowed, rounded to 1 decimal place (e.g., 2 borrowed out of 5 total → 40.0).
    • A class method from_entry(cls, entry) — takes a string in the format "Title:Copies" (e.g., "Python Basics:3"), parses it, converts copies to int, and returns a new Book.
    • A static method is_valid_isbn(isbn) — returns True if isbn is exactly 13 characters long and all characters are digits, False otherwise.
    • A class method total_available(cls) — returns the total number of available (not borrowed) copies across all books in _library.

Input

b1 = Book("Data Structures", 2)
b2 = Book.from_entry("Algorithms:3")

b1.borrow()
b1.borrow()
b1.borrow()
b1.return_book()

b2.borrow()
b2.return_book()
b2.return_book()

print(f"{b1.title}: available = {b1.available()}, usage = {b1.usage_percent()}%")
print(f"{b2.title}: available = {b2.available()}, usage = {b2.usage_percent()}%")

print(f"Valid ISBN '9781234567890': {Book.is_valid_isbn('9781234567890')}")
print(f"Valid ISBN '978-12345': {Book.is_valid_isbn('978-12345')}")
print(f"Total available in library: {Book.total_available()}")

Expected Output

[OK] borrow successful
[OK] borrow successful
[FAIL] borrow denied
[OK] return_book successful
[OK] borrow successful
[OK] return_book successful
[FAIL] return_book denied
Data Structures: available = 1, usage = 50.0%
Algorithms: available = 3, usage = 0.0%
Valid ISBN '9781234567890': True
Valid ISBN '978-12345': False
Total available in library: 4

Variant 4: Employee Task Tracker

A company needs a system to manage employee task assignments. The system should log every task assignment, validate employee codes, compute average performance scores, and support creating employees from HR records.

  1. Write a decorator log_action(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should print "[ACTION] {func.__name__} executed", call the original function with the same arguments, and return its result.
  2. Create a class Employee with:
    • __init__(self, name, emp_code) — stores the employee’s name, employee code, and initializes an empty dictionary _tasks (task_name → score as an integer).
    • A class variable _total_employees starting at 0, incremented in __init__ each time a new employee is created.
    • An instance method assign_task(self, task_name, score) decorated with @log_action — converts task_name to uppercase, then adds it to _tasks with the given score. Returns the string "{name} assigned {task_name} with score {score}".
    • An instance method avg_score(self) — computes and returns the average of all scores in _tasks, rounded to 1 decimal place. If no tasks exist, returns 0.0.
    • An instance method top_task(self) — returns the task name with the highest score. If no tasks exist, returns "No tasks".
    • A class method from_record(cls, data) — takes a string in the format "Name-Code" (e.g., "Sardor-3301001"), splits it, and returns a new Employee object.
    • A static method is_valid_code(emp_code) — returns True if the employee code is exactly 7 characters long and all characters are digits, False otherwise.
    • A class method total_employees(cls) — returns _total_employees.

Input

e1 = Employee("Sardor", "3301001")
e1.assign_task("report", 90)
e1.assign_task("analysis", 76)
e1.assign_task("design", 84)

e2 = Employee.from_record("Kamola-3301002")
e2.assign_task("Testing", 88)
e2.assign_task("review", 95)

print(f"{e1.name}: Avg = {e1.avg_score()}, Top = {e1.top_task()}")
print(f"{e2.name}: Avg = {e2.avg_score()}, Top = {e2.top_task()}")

print(f"Valid code '3301001': {Employee.is_valid_code('3301001')}")
print(f"Valid code '33B': {Employee.is_valid_code('33B')}")
print(f"Total employees: {Employee.total_employees()}")

Expected Output

[ACTION] assign_task executed
[ACTION] assign_task executed
[ACTION] assign_task executed
[ACTION] assign_task executed
[ACTION] assign_task executed
Sardor: Avg = 83.3, Top = REPORT
Kamola: Avg = 91.5, Top = REVIEW
Valid code '3301001': True
Valid code '33B': False
Total employees: 2

Variant 5: Athlete Training Tracker

A sports academy needs a system to manage athlete training sessions. The system should log every training session, validate athlete IDs, compute average intensity, and support creating athletes from roster strings.

  1. Write a decorator log_action(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should print "[ACTION] {func.__name__} executed", call the original function with the same arguments, and return its result.
  2. Create a class Athlete with:
    • __init__(self, name, athlete_id) — stores the athlete’s name, athlete ID, and initializes an empty dictionary _sessions (exercise_name → intensity as an integer).
    • A class variable _total_athletes starting at 0, incremented in __init__ each time a new athlete is created.
    • An instance method add_session(self, exercise, intensity) decorated with @log_action — converts exercise to uppercase, then adds it to _sessions with the given intensity. Returns the string "{name} trained {exercise} at intensity {intensity}".
    • An instance method avg_intensity(self) — computes and returns the average of all intensity values in _sessions, rounded to 1 decimal place. If no sessions exist, returns 0.0.
    • An instance method hardest_session(self) — returns the exercise name with the highest intensity. If no sessions exist, returns "No sessions".
    • A class method from_roster(cls, data) — takes a string in the format "Name-ID" (e.g., "Bobur-5501001"), splits it, and returns a new Athlete object.
    • A static method is_valid_id(athlete_id) — returns True if the athlete ID is exactly 7 characters long and all characters are digits, False otherwise.
    • A class method total_athletes(cls) — returns _total_athletes.

Input

a1 = Athlete("Bobur", "5501001")
a1.add_session("sprints", 95)
a1.add_session("weights", 80)
a1.add_session("swimming", 70)

a2 = Athlete.from_roster("Nilufar-5501002")
a2.add_session("Cycling", 82)
a2.add_session("sprints", 91)

print(f"{a1.name}: Avg = {a1.avg_intensity()}, Hardest = {a1.hardest_session()}")
print(f"{a2.name}: Avg = {a2.avg_intensity()}, Hardest = {a2.hardest_session()}")

print(f"Valid ID '5501001': {Athlete.is_valid_id('5501001')}")
print(f"Valid ID '55X': {Athlete.is_valid_id('55X')}")
print(f"Total athletes: {Athlete.total_athletes()}")

Expected Output

[ACTION] add_session executed
[ACTION] add_session executed
[ACTION] add_session executed
[ACTION] add_session executed
[ACTION] add_session executed
Bobur: Avg = 81.7, Hardest = SPRINTS
Nilufar: Avg = 86.5, Hardest = SPRINTS
Valid ID '5501001': True
Valid ID '55X': False
Total athletes: 2

Variant 6: Chef Recipe Tracker

A culinary school needs a system to manage chef recipe submissions. The system should log every recipe submission, validate chef license numbers, compute average ratings, and support creating chefs from enrollment strings.

  1. Write a decorator log_action(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should print "[ACTION] {func.__name__} executed", call the original function with the same arguments, and return its result.
  2. Create a class Chef with:
    • __init__(self, name, license_no) — stores the chef’s name, license number, and initializes an empty dictionary _recipes (recipe_name → rating as an integer).
    • A class variable _total_chefs starting at 0, incremented in __init__ each time a new chef is created.
    • An instance method submit_recipe(self, recipe_name, rating) decorated with @log_action — converts recipe_name to uppercase, then adds it to _recipes with the given rating. Returns the string "{name} submitted {recipe_name} rated {rating}".
    • An instance method avg_rating(self) — computes and returns the average of all ratings in _recipes, rounded to 1 decimal place. If no recipes exist, returns 0.0.
    • An instance method best_recipe(self) — returns the recipe name with the highest rating. If no recipes exist, returns "No recipes".
    • A class method from_enrollment(cls, data) — takes a string in the format "Name-License" (e.g., "Zulfiya-7701001"), splits it, and returns a new Chef object.
    • A static method is_valid_license(license_no) — returns True if the license number is exactly 7 characters long and all characters are digits, False otherwise.
    • A class method total_chefs(cls) — returns _total_chefs.

Input

c1 = Chef("Zulfiya", "7701001")
c1.submit_recipe("plov", 93)
c1.submit_recipe("lagman", 87)
c1.submit_recipe("shashlik", 79)

c2 = Chef.from_enrollment("Otabek-7701002")
c2.submit_recipe("Somsa", 96)
c2.submit_recipe("manti", 85)

print(f"{c1.name}: Avg = {c1.avg_rating()}, Best = {c1.best_recipe()}")
print(f"{c2.name}: Avg = {c2.avg_rating()}, Best = {c2.best_recipe()}")

print(f"Valid license '7701001': {Chef.is_valid_license('7701001')}")
print(f"Valid license '77Z': {Chef.is_valid_license('77Z')}")
print(f"Total chefs: {Chef.total_chefs()}")

Expected Output

[ACTION] submit_recipe executed
[ACTION] submit_recipe executed
[ACTION] submit_recipe executed
[ACTION] submit_recipe executed
[ACTION] submit_recipe executed
Zulfiya: Avg = 86.3, Best = PLOV
Otabek: Avg = 90.5, Best = SOMSA
Valid license '7701001': True
Valid license '77Z': False
Total chefs: 2

Variant 7: Medicine Inventory System

A pharmacy needs a system to manage medicine stock. The system should log stock changes, validate medicine codes, compute total inventory value, and support creating medicines from supplier lists.

  1. Write a decorator track_change(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should call the original function with the same arguments, capture its return value, print "[STOCK] {return_value}", and return the result.
  2. Create a class Medicine with:
    • __init__(self, name, price, quantity) — stores the medicine name, price (float), and quantity (int).
    • A class variable _all_medicines — an empty list that collects every Medicine instance created (append self in __init__).
    • An instance method receive(self, amount) decorated with @track_change — adds amount to quantity and returns the string "{name}: received {amount}, now {quantity}".
    • An instance method dispense(self, amount) decorated with @track_change — if amount is greater than quantity, returns the string "Not enough {name} available" without changing quantity. Otherwise, subtracts amount from quantity and returns "{name}: dispensed {amount}, now {quantity}".
    • An instance method total_value(self) — returns price * quantity rounded to 2 decimal places.
    • A class method from_supplier(cls, entry) — takes a string in the format "Name:Price:Quantity" (e.g., "Aspirin:12.50:100"), parses it, converts price to float and quantity to int, and returns a new Medicine.
    • A static method is_valid_code(code) — returns True if code starts with "MED-" and the rest are digits (e.g., "MED-045"), False otherwise.
    • A class method pharmacy_value(cls) — returns the sum of total_value() for all medicines in _all_medicines, rounded to 2 decimal places.

Input

m1 = Medicine("Paracetamol", 8.75, 50)
m2 = Medicine.from_supplier("Ibuprofen:12.30:30")

m1.receive(20)
m1.dispense(45)
m1.dispense(100)
m2.dispense(10)

print(f"{m1.name}: value = ${m1.total_value()}")
print(f"{m2.name}: value = ${m2.total_value()}")

print(f"Valid code 'MED-045': {Medicine.is_valid_code('MED-045')}")
print(f"Valid code 'RX-100': {Medicine.is_valid_code('RX-100')}")
print(f"Pharmacy total: ${Medicine.pharmacy_value()}")

Expected Output

[STOCK] Paracetamol: received 20, now 70
[STOCK] Paracetamol: dispensed 45, now 25
[STOCK] Not enough Paracetamol available
[STOCK] Ibuprofen: dispensed 10, now 20
Paracetamol: value = $218.75
Ibuprofen: value = $246.0
Valid code 'MED-045': True
Valid code 'RX-100': False
Pharmacy total: $464.75

Variant 8: Food Supply Tracker

A restaurant chain needs a system to manage food ingredient supplies. The system should log supply changes, validate supplier codes, compute total supply cost, and support creating ingredients from order forms.

  1. Write a decorator track_change(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should call the original function with the same arguments, capture its return value, print "[STOCK] {return_value}", and return the result.
  2. Create a class Ingredient with:
    • __init__(self, name, cost_per_unit, units) — stores the ingredient name, cost per unit (float), and units (int).
    • A class variable _all_ingredients — an empty list that collects every Ingredient instance created (append self in __init__).
    • An instance method order(self, amount) decorated with @track_change — adds amount to units and returns the string "{name}: ordered {amount}, now {units}".
    • An instance method use(self, amount) decorated with @track_change — if amount is greater than units, returns the string "Not enough {name} in kitchen" without changing units. Otherwise, subtracts amount from units and returns "{name}: used {amount}, now {units}".
    • An instance method total_cost(self) — returns cost_per_unit * units rounded to 2 decimal places.
    • A class method from_order_form(cls, entry) — takes a string in the format "Name:Cost:Units" (e.g., "Flour:2.50:40"), parses it, converts cost to float and units to int, and returns a new Ingredient.
    • A static method is_valid_code(code) — returns True if code starts with "ING-" and the rest are digits (e.g., "ING-012"), False otherwise.
    • A class method kitchen_value(cls) — returns the sum of total_cost() for all ingredients in _all_ingredients, rounded to 2 decimal places.

Input

i1 = Ingredient("Rice", 3.20, 60)
i2 = Ingredient.from_order_form("Olive Oil:15.75:8")

i1.order(15)
i1.use(50)
i1.use(100)
i2.use(3)

print(f"{i1.name}: cost = ${i1.total_cost()}")
print(f"{i2.name}: cost = ${i2.total_cost()}")

print(f"Valid code 'ING-012': {Ingredient.is_valid_code('ING-012')}")
print(f"Valid code 'FD-999': {Ingredient.is_valid_code('FD-999')}")
print(f"Kitchen total: ${Ingredient.kitchen_value()}")

Expected Output

[STOCK] Rice: ordered 15, now 75
[STOCK] Rice: used 50, now 25
[STOCK] Not enough Rice in kitchen
[STOCK] Olive Oil: used 3, now 5
Rice: cost = $80.0
Olive Oil: cost = $78.75
Valid code 'ING-012': True
Valid code 'FD-999': False
Kitchen total: $158.75

Variant 9: Stationery Supply Manager

An office needs a system to manage stationery supplies. The system should log supply changes, validate item codes, compute total supply cost, and support creating items from purchase orders.

  1. Write a decorator track_change(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should call the original function with the same arguments, capture its return value, print "[STOCK] {return_value}", and return the result.
  2. Create a class Supply with:
    • __init__(self, name, unit_price, stock) — stores the supply name, unit price (float), and stock (int).
    • A class variable _all_supplies — an empty list that collects every Supply instance created (append self in __init__).
    • An instance method add_stock(self, amount) decorated with @track_change — adds amount to stock and returns the string "{name}: added {amount}, now {stock}".
    • An instance method distribute(self, amount) decorated with @track_change — if amount is greater than stock, returns the string "Not enough {name} in storage" without changing stock. Otherwise, subtracts amount from stock and returns "{name}: distributed {amount}, now {stock}".
    • An instance method total_cost(self) — returns unit_price * stock rounded to 2 decimal places.
    • A class method from_purchase_order(cls, entry) — takes a string in the format "Name:Price:Stock" (e.g., "Pens:1.25:200"), parses it, converts price to float and stock to int, and returns a new Supply.
    • A static method is_valid_code(code) — returns True if code starts with "SUP-" and the rest are digits (e.g., "SUP-007"), False otherwise.
    • A class method office_value(cls) — returns the sum of total_cost() for all supplies in _all_supplies, rounded to 2 decimal places.

Input

s1 = Supply("Notebooks", 4.50, 40)
s2 = Supply.from_purchase_order("Markers:2.80:25")

s1.add_stock(10)
s1.distribute(35)
s1.distribute(100)
s2.distribute(5)

print(f"{s1.name}: cost = ${s1.total_cost()}")
print(f"{s2.name}: cost = ${s2.total_cost()}")

print(f"Valid code 'SUP-007': {Supply.is_valid_code('SUP-007')}")
print(f"Valid code 'OFF-010': {Supply.is_valid_code('OFF-010')}")
print(f"Office total: ${Supply.office_value()}")

Expected Output

[STOCK] Notebooks: added 10, now 50
[STOCK] Notebooks: distributed 35, now 15
[STOCK] Not enough Notebooks in storage
[STOCK] Markers: distributed 5, now 20
Notebooks: cost = $67.5
Markers: cost = $56.0
Valid code 'SUP-007': True
Valid code 'OFF-010': False
Office total: $123.5

Variant 10: Equipment Rental Manager

A rental shop needs a system to manage equipment lending. The system should log rent and return actions, validate equipment serial numbers, compute availability, and support creating equipment from inventory sheets.

  1. Write a decorator log_operation(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should call the original function with the same arguments, capture its return value. If the return value is True, print "[OK] {func.__name__} successful". If False, print "[FAIL] {func.__name__} denied". Return the result.
  2. Create a class Equipment with:
    • __init__(self, name, total_units) — stores the name, total number of units (int), initializes _rented to 0, and appends self to the class variable _inventory.
    • A class variable _inventory — an empty list that collects every Equipment instance created.
    • An instance method rent(self) decorated with @log_operation — if _rented is already equal to total_units, returns False. Otherwise, increments _rented by 1 and returns True.
    • An instance method return_item(self) decorated with @log_operation — if _rented is 0, returns False. Otherwise, decrements _rented by 1 and returns True.
    • An instance method available(self) — returns total_units - _rented.
    • An instance method rental_rate(self) — returns the percentage of units currently rented, rounded to 1 decimal place (e.g., 2 rented out of 5 total → 40.0).
    • A class method from_sheet(cls, entry) — takes a string in the format "Name:Units" (e.g., "Drill:4"), parses it, converts units to int, and returns a new Equipment.
    • A static method is_valid_serial(serial) — returns True if serial is exactly 13 characters long and all characters are digits, False otherwise.
    • A class method total_available(cls) — returns the total number of available (not rented) units across all equipment in _inventory.

Input

e1 = Equipment("Projector", 2)
e2 = Equipment.from_sheet("Camera:3")

e1.rent()
e1.rent()
e1.rent()
e1.return_item()

e2.rent()
e2.return_item()
e2.return_item()

print(f"{e1.name}: available = {e1.available()}, rental = {e1.rental_rate()}%")
print(f"{e2.name}: available = {e2.available()}, rental = {e2.rental_rate()}%")

print(f"Valid serial '1234567890123': {Equipment.is_valid_serial('1234567890123')}")
print(f"Valid serial '123-456': {Equipment.is_valid_serial('123-456')}")
print(f"Total available in shop: {Equipment.total_available()}")

Expected Output

[OK] rent successful
[OK] rent successful
[FAIL] rent denied
[OK] return_item successful
[OK] rent successful
[OK] return_item successful
[FAIL] return_item denied
Projector: available = 1, rental = 50.0%
Camera: available = 3, rental = 0.0%
Valid serial '1234567890123': True
Valid serial '123-456': False
Total available in shop: 4

Variant 11: Ticket Booth Manager

A theater needs a system to manage ticket sales. The system should log sell and refund actions, validate booking codes, compute seat availability, and support creating shows from schedule entries.

  1. Write a decorator log_operation(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should call the original function with the same arguments, capture its return value. If the return value is True, print "[OK] {func.__name__} successful". If False, print "[FAIL] {func.__name__} denied". Return the result.
  2. Create a class Show with:
    • __init__(self, title, total_seats) — stores the title, total number of seats (int), initializes _sold to 0, and appends self to the class variable _schedule.
    • A class variable _schedule — an empty list that collects every Show instance created.
    • An instance method sell_ticket(self) decorated with @log_operation — if _sold is already equal to total_seats, returns False. Otherwise, increments _sold by 1 and returns True.
    • An instance method refund_ticket(self) decorated with @log_operation — if _sold is 0, returns False. Otherwise, decrements _sold by 1 and returns True.
    • An instance method seats_left(self) — returns total_seats - _sold.
    • An instance method sold_percent(self) — returns the percentage of seats currently sold, rounded to 1 decimal place (e.g., 2 sold out of 5 total → 40.0).
    • A class method from_schedule(cls, entry) — takes a string in the format "Title:Seats" (e.g., "Hamlet:3"), parses it, converts seats to int, and returns a new Show.
    • A static method is_valid_booking(code) — returns True if code is exactly 13 characters long and all characters are digits, False otherwise.
    • A class method total_seats_left(cls) — returns the total number of available (unsold) seats across all shows in _schedule.

Input

s1 = Show("Romeo and Juliet", 2)
s2 = Show.from_schedule("Hamlet:3")

s1.sell_ticket()
s1.sell_ticket()
s1.sell_ticket()
s1.refund_ticket()

s2.sell_ticket()
s2.refund_ticket()
s2.refund_ticket()

print(f"{s1.title}: seats left = {s1.seats_left()}, sold = {s1.sold_percent()}%")
print(f"{s2.title}: seats left = {s2.seats_left()}, sold = {s2.sold_percent()}%")

print(f"Valid booking '4567890123456': {Show.is_valid_booking('4567890123456')}")
print(f"Valid booking '456-789': {Show.is_valid_booking('456-789')}")
print(f"Total seats left: {Show.total_seats_left()}")

Expected Output

[OK] sell_ticket successful
[OK] sell_ticket successful
[FAIL] sell_ticket denied
[OK] refund_ticket successful
[OK] sell_ticket successful
[OK] refund_ticket successful
[FAIL] refund_ticket denied
Romeo and Juliet: seats left = 1, sold = 50.0%
Hamlet: seats left = 3, sold = 0.0%
Valid booking '4567890123456': True
Valid booking '456-789': False
Total seats left: 4

Variant 12: Parking Lot Manager

A parking garage needs a system to manage parking spots. The system should log entry and exit actions, validate license plates, compute occupancy, and support creating lots from city records.

  1. Write a decorator log_operation(func) that defines a wrapper(*args, **kwargs) inside. The wrapper should call the original function with the same arguments, capture its return value. If the return value is True, print "[OK] {func.__name__} successful". If False, print "[FAIL] {func.__name__} denied". Return the result.
  2. Create a class ParkingLot with:
    • __init__(self, location, total_spots) — stores the location, total number of spots (int), initializes _occupied to 0, and appends self to the class variable _all_lots.
    • A class variable _all_lots — an empty list that collects every ParkingLot instance created.
    • An instance method enter(self) decorated with @log_operation — if _occupied is already equal to total_spots, returns False. Otherwise, increments _occupied by 1 and returns True.
    • An instance method exit_lot(self) decorated with @log_operation — if _occupied is 0, returns False. Otherwise, decrements _occupied by 1 and returns True.
    • An instance method free_spots(self) — returns total_spots - _occupied.
    • An instance method occupancy_rate(self) — returns the percentage of spots currently occupied, rounded to 1 decimal place (e.g., 2 occupied out of 5 total → 40.0).
    • A class method from_record(cls, entry) — takes a string in the format "Location:Spots" (e.g., "Downtown:3"), parses it, converts spots to int, and returns a new ParkingLot.
    • A static method is_valid_plate(plate) — returns True if plate is exactly 13 characters long and all characters are digits, False otherwise.
    • A class method total_free(cls) — returns the total number of free spots across all lots in _all_lots.

Input

l1 = ParkingLot("Central Mall", 2)
l2 = ParkingLot.from_record("Airport:3")

l1.enter()
l1.enter()
l1.enter()
l1.exit_lot()

l2.enter()
l2.exit_lot()
l2.exit_lot()

print(f"{l1.location}: free = {l1.free_spots()}, occupancy = {l1.occupancy_rate()}%")
print(f"{l2.location}: free = {l2.free_spots()}, occupancy = {l2.occupancy_rate()}%")

print(f"Valid plate '0123456789012': {ParkingLot.is_valid_plate('0123456789012')}")
print(f"Valid plate '012-345': {ParkingLot.is_valid_plate('012-345')}")
print(f"Total free spots: {ParkingLot.total_free()}")

Expected Output

[OK] enter successful
[OK] enter successful
[FAIL] enter denied
[OK] exit_lot successful
[OK] enter successful
[OK] exit_lot successful
[FAIL] exit_lot denied
Central Mall: free = 1, occupancy = 50.0%
Airport: free = 3, occupancy = 0.0%
Valid plate '0123456789012': True
Valid plate '012-345': False
Total free spots: 4