Створіть generic клас Spellbook, де T — тип заклинання, що реалізує інтерфейс ISpell з методами Cast() та GetPower(). Застосуйте комбіновані constraints: where T : ISpell, new(), IComparable для сортування заклинань за силою, і додайте метод LearnSpell(), що додає нові заклинання з перевіркою на унікальність через IComparable.
У Main() створіть Spellbook з вигаданими заклинаннями (клас Fireball та HealingWave, обидва з ISpell), або по Гарі Потеру. вивчіть 5 заклинань, відсортуйте та симулюйте кастування найсильнішого, виводячи ефекти. Додайте умовні constraints через where T : class для "темних" заклять (з додатковим інтерфейсом IDarkMagic), і метод InvokeRitual(), що комбінує заклинання лише якщо всі T задовольняють IDarkMagic, інакше кидає виняток. Тестуйте з мішаними типами в окремій Spellbook.