G. Классный прямоугольник 3.0

Необходимо ещё немного доработать предыдущую задачу.

Разработайте методы:

  • turn() — поворачивает прямоугольник на 90° по часовой стрелке вокруг его центра;
  • scale(factor) — изменяет размер в указанное количество раз, тоже относительно центра.

Все вычисления производить с округлением до сотых.

Примечание

Ваше решение должно содержать только классы и функции.
В решении не должно быть вызовов инициализации требуемых классов.
Все результаты вычислений нужно округлить до сотых.

Пример

Ввод

rect = Rectangle((3.14, 2.71), (-3.14, -2.71))
print(rect.get_pos(), rect.get_size(), sep='\n')
rect.turn()
print(rect.get_pos(), rect.get_size(), sep='\n')

Вывод

(-3.14, 2.71)
(6.28, 5.42)
(-2.71, 3.14)
(5.42, 6.28)

Ввод

rect = Rectangle((3.14, 2.71), (-3.14, -2.71))
print(rect.get_pos(), rect.get_size(), sep='\n')
rect.scale(2.0)
print(rect.get_pos(), rect.get_size(), sep='\n')

Вывод

(-3.14, 2.71)
(6.28, 5.42)
(-6.28, 5.42)
(12.56, 10.84)

Решение

Продолжение задач про прямоугольник. Приведу лишь решение для класса, описанного через точку и ширину/высоту. Если интересно, почему и как работают методы изменения размера и поворота, приглашаю попробовать нарисовать их на бумаге и на картинке прописать где какие данные используются. Это будет прекрасная тренировка на то, как можно решать задачи альтернативными от классических формул методами. Зачастую такой путь бывает более простым и коротким, но очень важно следить, чтобы он оставался математически и логически безупречным, иначе можно породить алгоритм, который будет будет содержать ошибку и который будет очень сложно отладить в силу его кажущейся очевидности.

Обратите внимание, что мы теперь не просто используем класс Point, а наследуем от него наш прямоугольник.

Посмотреть код

Решение

Python
class Point:
    def __init__(self, x, y):
        self.x = round(x, 2)
        self.y = round(y, 2)
        self.round()

    def round(self):
        self.x = round(self.x, 2)
        self.y = round(self.y, 2)
        return self


class Rectangle(Point):
    def __init__(self, corner1, corner2):
        self.x = min(corner1[0], corner2[0])
        self.y = max(corner1[1], corner2[1])
        self.width = round(max(corner1[0], corner2[0]) - self.x, 2)
        self.height = round(self.y - min(corner1[1], corner2[1]), 2)

    def perimeter(self):
        return round((self.width + self.height) * 2, 2)

    def area(self):
        return round(self.width * self.height, 2)

    def get_pos(self):
        return self.x, self.y

    def get_size(self):
        return self.width, self.height

    def move(self, dx, dy):
        self.x += dx
        self.y += dy
        self.round()

    def resize(self, width, height):
        self.width = round(width, 2)
        self.height = round(height, 2)

    def turn(self):
        delta = round((self.width - self.height) / 2, 2)
        self.move(delta, delta)
        self.height, self.width = self.width, self.height

    def scale(self, ratio):
        dx = round((self.width * (ratio - 1)), 2)
        dy = round((self.height * (ratio - 1)), 2)
        self.move(-dx / 2, dy / 2)
        self.resize(self.width * ratio, self.height * ratio)
Подписаться
Уведомить о
guest
10 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
VVV
VVV
24.06.2024 22:52

Просто ушлепская задача, с округлением. Это просто чудо что она прошла тесты!

VVV
VVV
Ответить на  Сергей Клочко
28.06.2024 16:32

абсолютно с тобой с тобой согласен. Способов может быть много и зачем каждое действие округлять непонятно. Гораздо точнее производить вычисления и хранить их с точностью который позволяет тип float в python а результат выводить округленным.

konchenayaregistracia
konchenayaregistracia
25.06.2024 20:02

Без класса Point

class Rectangle:

def __init__(self, corner1, corner2):
self.x, self.y = round(min(corner1[0], corner2[0]), 2), round(min(corner1[1], corner2[1]), 2)
self.width, self.height = round(abs(corner1[0] – corner2[0]), 2), round(abs(corner1[1] – corner2[1]), 2)

def perimeter(self):
return round((self.width + self.height) * 2, 2)

def area(self):
return round(self.width * self.height, 2)

def get_pos(self):
return self.x, self.y + self.height

def get_size(self):
return self.width, self.height

def move(self, dx, dy):
self.x, self.y = round(self.x + dx, 2), round(self.y + dy, 2)

def resize(self, width, height):
self.width, self.height = round(width, 2), round(height, 2)

def turn(self):
cx, cy = self.x + self.width / 2, self.y + self.height / 2
self.width, self.height = self.height, self.width
self.x, self.y = round(cx – self.width / 2, 2), round(cy – self.height / 2, 2)

def scale(self, ratio):
cx, cy = self.x + self.width / 2, self.y + self.height / 2
self.width, self.height = round(self.width * ratio, 2), round(self.height * ratio, 2)
self.x, self.y = round(cx – self.width / 2, 2), round(cy – self.height / 2, 2)

Иван
Иван
01.08.2024 21:04

Спасибо за решение. Описал класс Rectangle как у вас во втором решении, но без использования класса Point.

class Rectangle:

    def __init__(self, point1, point2):
        self.position = [min(point1[0], point2[0]), max(point1[1], point2[1])]
        self.width= abs(point1[0] – point2[0])
        self.height= abs(point1[1] – point2[1])

И думаю, что округлять лучше в методах класса при выводе ответа, иначе все операции будут производиться уже с округлёнными данными (длиной и высотой прямоугольника), что будет давать лишнюю погрешность.

Денис
Денис
Ответить на  Сергей Клочко
29.11.2024 18:44

Установка ТЗ “Округлять в каждом действии” не является корректной, пока в ТЗ действия не будут описаны.
Я могу сделать периметр:
P = (a + b) * 2,
P = 2*a + 2*b
P = a + a + b + b
Все эти варианты являются математически однозначными, и даже, я бы сказал, от ситуации и языка зависит, какой лучше, ибо, например, 3 сложения быстрее, чем 2 умножения и сложение.
И это самый простой пример, конечно, здесь сложение и умножение не меняют точности, однако суть проблемы обозначена прекрасно.
Если ТЗ не говорит о том, что величину надо считать по конкретной формуле без права на математические преобразования, утверждение “округлять при каждом действии” просто бред.

Последний раз редактировалось 26 дней назад Денис ем
Степан
15.08.2024 18:40

Может ли кто-то дать подсказку? Первые два теста проходит, в третьем выдает ошибку.
class Rectangle:

def __init__(self, corner_1: tuple, corner_2: tuple):
self.corner_1 = corner_1
self.corner_2 = corner_2
self.left_x = min(self.corner_1[0], self.corner_2[0])
self.left_y = max(self.corner_1[1], self.corner_2[1])
self.width = abs(self.corner_2[0] – self.corner_1[0])
self.length = abs(self.corner_2[1] – self.corner_1[1])
self.x_center = round(self.left_x + self.width / 2.0, 2)
self.y_center = round(self.left_y – self.length / 2.0, 2)

def get_size(self):
return tuple((round(self.width, 2), round(self.length, 2)))

def move(self, dx, dy):
self.left_x += dx
self.left_y += dy

def get_pos(self):
return tuple((round(self.left_x, 2), round(self.left_y, 2)))

def resize(self, width, height):
self.width = width
self.length = height

def perimeter(self):
return round((self.width + self.length) * 2, 2)

def area(self):
return round(self.width * self.length, 2)

def turn(self):
width = self.length
length = self.width
self.left_x = self.x_center – width / 2.0
self.left_y = self.y_center + length / 2.0
self.length = length
self.width = width

def scale(self, factor):
self.width *= factor
self.length *= factor
self.left_x = self.x_center – self.width / 2.0
self.left_y = self.y_center + self.length / 2.0

Степан
Ответить на  Сергей Клочко
15.08.2024 20:44

Вы правы, проблема оказалось в том, что я не округлял вот здесь:

self.width *= factor
self.length *= factor

Спасибо!