11. Игра геометрические фигуры.
Условие:
Пример работы программы:
- Привет! Мы фигуры и у нас есть 2 вопроса.
- Играем Y/N: y
- Окружность с радиусом 9
- Укажите площадь этой фигуры: 2
- Ошибка! Правильный ответ: 254.34.
- Укажите периметр этой фигуры: 5
- Ошибка! Правильный ответ: 56.52.
- Играем Y/N: y
- Квадрат со стороной 7
- Укажите площадь этой фигуры: 49
- Правильно!
- Укажите периметр этой фигуры: 28
- Правильно!
- Играем Y/N: n
- Игра окончена.
Необходимо создать абстрактный класс, в котором обязательными методами для описания являются:
- метод подсчёта периметра фигуры;
- метод подсчёта площади фигуры;
- метод, который возвращает название фигуры.
Необходимо создать класс-наследник Circle (окружность) от базового абстрактного класса, в котором будет необходимо описать соответствующие методы для расчёта площади и периметра, а также один из методов будет возвращать название фигуры.
Необходимо создать класс-наследник Rectangul (прямоугольник) от базового абстрактного класса, в котором будет необходимо описать соответствующие методы для расчёта площади и периметра, а также один из методов будет возвращать название фигуры.
Необходимо создать класс-наследник Square (квадрат) от базового класса Rectangul (прямоугольник), который будет наследовать соответствующие методы для расчёта площади и периметра, а также один из методов для возврата названия фигуры будет переопределён.
Также создадим класс Game, который будет иметь атрибут QUESTION_COUNT равный 2. В этом классе создание объектов класса недопустимо. Также этот класс будет содержать несколько методов:
- первый метод будет рандомно определять одну из трёх возможных фигур и параметры для них, такие как радиус или стороны, в зависимости от фигуры;
- второй метод будет определять правильно ли пользователь ввел ответ;
- третий метод будет управлять первым и вторым;
- четвёртый метод нужен для старта программы и спрашивает пользователя о желании сыграть в игру.
Код:
import abc, random
class IShape(abc.ABC): # создание абстрактного класса, методы в подклассах которого нужно обязательно описать
'''Интерфейс для реализации геометрических фигур'''
@abc.abstractmethod
def get_perimeter(self):
'''Возвращает периметр фигуры'''
pass
@abc.abstractmethod
def get_area(self):
'''Возвращает площадь фигуры'''
pass
@abc.abstractmethod
def get_description(self):
'''Возвращает произвольное описание фигуры'''
pass
class Circle(IShape): # создание подкласса, в котором супер-классом является IShape
PI = 3.14 # создание константы в атрибутах класса, не воспользовался библиотекой math для тренировки ООП
def __init__(self, radius): # обязательное описание метода в подклассе
self._radius = radius
def get_perimeter(self): # обязательное описание метода в подклассе
return float(round(2 * self.__class__.PI * self._radius, 2)) # self.__class__.PI - такая запись обращается к классу (самому себе) динамически
def get_area(self): # обязательное описание метода в подклассе
return float(round(self.__class__.PI * self._radius ** 2, 2))
def get_description(self): # обязательное описание метода в подклассе
return f"Окружность с радиусом {self._radius}"
class Rectangul(IShape): # создание подкласса, в котором супер-классом является IShape
def __init__(self, width, height): # обязательное описание метода в подклассе
self._width = width
self._height = height
def get_perimeter(self): # обязательное описание метода в подклассе
return float(round(2 * (self._width + self._height), 2)) # self.__class__.PI - такая запись обращается к классу (самому себе) динамически
def get_area(self): # обязательное описание метода в подклассе
return float(round(self._width * self._height, 2))
def get_description(self): # обязательное описание метода в подклассе
return f"Прямоугольник с высотой {self._width} и шириной {self._height}"
class Square(Rectangul): # создание подкласса, в котором супер-классом является IShape
def __init__(self, side): # обязательное описание метода в подклассе
super().__init__(side, side) # поскольку у нас фигура квадрат, то мы передаём его сторону в качестве параметра старшему классу два раза
# два метода get_perimeter и get_area описывать не нужно, они будут наследоваться.
def get_description(self): # обязательное описание метода в подклассе
return f"Квадрат со стороной {self._width}" # состояние атрибута находится в старшем классе в переменной self._width
class Game:
QUESTION_COUNT = 2
def __init__(self):
raise Exception("Нельзя создать экземпляр данного класса!")
@staticmethod
def __get_shape(): # создан приватный метод, доступен только внутри класса
x = random.randint(1, 3)
if x == 1:
return Circle(random.randint(1, 10))
if x == 2:
return Rectangul(random.randint(1, 10), random.randint(1, 10))
if x == 3:
return Square(random.randint(1, 10))
@staticmethod
def __calculate(string, answer): # создан приватный метод, доступен только внутри класса
while True:
try:
guess = float(input(f"Укажите {string} этой фигуры: "))
break
except:
print("Ошибка! Повторите ввод.")
if guess == answer:
print("Правильно!")
else:
print(f"Ошибка! Правильный ответ: {answer}.")
@ classmethod
def __run(cls): # создан приватный метод, доступен только внутри класса
shape = cls.__get_shape() # создаём объект рандомный из трёх классов Circle, Rectangul, Square
print(shape.get_description())
cls.__calculate("площадь", shape.get_area())
cls.__calculate("периметр", shape.get_perimeter())
@classmethod
def play(cls):
print()
print(f"Привет! Мы фигуры и у нас есть {cls.QUESTION_COUNT} вопроса.")
while True:
is_game_over = input("Играем Y/N: ").upper()
if is_game_over == "N":
break
cls.__run()
print("Игра окончена.")
print()
Game.play()