Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

Lab 9: ООП и пушка 2

Лаба: http://cs.mipt.ru/python/lessons/lab9.html.

В качестве задания достаточно решить любую задачу.

Задача 1 (Библиотека)

Источник.

В библиотеках хранятся книги. У каждой книги есть название, а также автор, и дата выпуска. У каждой библиотеки тоже есть название. В библиотеке может быть больше одного экземпляра книги с теми же названием и автором. Надо определить классы для Книги и Библиотеки.

При этом должна быть возможность добавить книгу в библиотеку с помощью операции +. При сложении библиотеки и книги получается новая библиотека с тем же названием, что у библиотеки-слагаемого, но у которой среди книг есть ещё одна — книга-слагаемое. Например:

biblio = Library(name="Библиотека МФТИ")
book = Book(
    name="Теоретическая физика. Том 1. Механика",
    author="Ландау Л.Д., Лифшиц Е.М.",
    year=2004
)

biblio = biblio + book  # Теперь в библиотеке biblio есть одна книга

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

biblio1 = Library(name="Библиотека МФТИ")
biblio2 = Library(name="Ленинка")
book = Book(
    name="Ведьма", author="Фриц Лейбер", year=1943
)

biblio1 = biblio1 + book
biblio2 = biblio2 + book

print(biblio1 > biblio2)   # False
print(biblio1 == biblio2)  # True, так как 1 == 1

biblio1 += book

print(biblio1 > biblio2)   # True, так как 2 > 1
print(biblio1 == biblio2)  # False

У библиотеки должен быть "читаемый" вывод при использовании print. Например:

biblio = Library(name="Библиотека МФТИ")
book = Book(
    name="Дважды умершая (Повесть о том, как любящая Чжоу Шэн-сянь привела в смятение лавку Фаней)",
    author="-", year=1600
)

biblio = biblio + book

print(biblio)  # Библиотека МФТИ (число книг: 1)

Задача 2 (ℚ)

Источник.

Нужно определить класс Рационального числа: число определяется числителем (целое число) и знаменателем (натуральное число), должны быть методы по сложению, вычитанию, умножению и делению рациональных чисел. Также должен быть метод по переводу рационального числа в обычное float число (например объект, представляющий число 1/8 должен отобразиться в 0.125). Например:

r1 = Rational(1, 2)
r2 = Rational(-1, 2)

print(r1 * r2)    # -1/4
print(float(r1))  # 0.5

Задача 3 («Точки в полярных координатах»)

Источник.

Надо реализовать класс Point для представления точек в полярной системе координат на плоскости. Точка в полярной системе координат определяется расстоянием до полюса r и углом φ между направлением на точку из полюса и заранее выбранным направлением l. Расстояние будем считать безразмерным, а угол — выраженным в градусах. Например, создание объекта, представляющего точку, удалённую от полюса на расстояние 10 под углом в 30 градусов:

p = Point(r=10, phi=30)

Должна быть возможность складывать точки. При сложении двух точек складываются их радиусы-векторы по правилу сложения векторов. И координатами точки-результата будут: длина результирующего вектора и угол, который он образует с направлением l. Например:

p1 = Point(r=1, phi=0)
p2 = Point(r=1, phi=90)
p3 = p1 + p2  # точка с r = 1.41 (примерно) и phi = 45

У точки Point должно быть понятное представление при выводе с помощью print. Например:

p = Point(1, 10)

print(p)  # (r = 1, φ = 10)

Также должна быть возможность проверить две точки на равенство. Объекты класса Point точки p1 и p2 равны, если они представляют одну и ту же точку плоскости:

p1 = Point(1, 120)
p2 = Point(1, 480)

print(p1 == p2)  # True

Задача 4 («Кино»)

Источник.

Люди любят смотреть кино, однако данному человеку фильм может быть не рекомендован к просмотру из-за возрастного ограничения...

Фильм (Movie) определяется следующими признаками:

  • название (строка)
  • режиссёр (строка)
  • год выпуска (целое число)
  • страна (строка)
  • продолжительность в минутах (целое число)
  • возрастной рейтинг — минимальный допустимый возраст для просмотра (целое число)

У человека же (Human) есть следующие атрибуты:

  • имя
  • пол
  • год рождения

Чтобы понять, можно ли данному человеку human смотреть фильм movie, у каждого фильма должен быть метод is_allowed(human), который возвращает True или False в зависимости от того, разрешено или нет человеку смотреть фильм:

movie = Movie(
  name="Это безумный, безумный, безумный, безумный мир",
  director="Стэнли Крамер", year=1963,
  country="США", duration=210, age_rating=6
)
human = Human(name="Нео", sex="М", year_of_birth=1964)

print(movie.is_allowed(human))  # True (сейчас 2023 год, поэтому Нео точно можно смотреть любые фильмы)

Также можно выделить "особого вида фильмы": мультфильмы (Cartoon). Как фильмы, у которых есть ещё один атрибут "техника создания" technique (рисованный, пластилиновый, ...). Среди мультфильмов же отдельно можно выделить ещё аниме (Anime) — как рисованные мультфильмы, у которых страной производства всегда является Япония.

Надо реализовать описанные классы Human, Movie, Cartoon, и Anime.

Задача 5 («Салон»)

Источник.

Люди приходят в салон красоты, где работают разные специалисты...

Будем считать, что человек (Human) обладает следующими характеристиками:

  • имя (строка)
  • возраст (целое число)
  • пол (строка; два возможных значения: "M" и "F")
  • средняя длина волос в сантиметрах (целое число)
  • средняя длина ногтей в миллиметрах (целое число)
  • цвет ногтей (строка; по умолчанию — бесцветные)

Все сотрудники салона умеют выполнять свою работу do_job(human). Но работа у всех разная. Так, в салоне работают следующие специалисты:

  • Мастер маникюра: уменьшает длину ногтей на 1 (если можно уменьшить) и красит ногти в случайный цвет (красный, фиолетовый или зелёный)
  • Парикмахер: уменьшает длину волос на 1 (если можно уменьшить)
  • Барбер: как парикмахер, но стрижёт только мужчин. Если приходит женщина — то бросает исключение ValueError.

Например:

neo = Human(
  name="Neo", sex="M", year_of_birth=1964,
  hair_length=10, nail_length=2
)
trinity = Human(
  name="Trinity", sex="F", year_of_birth=1967,
  hair_length=30, nail_length=5
)

manicurist = Manicurist(name="Samara", sex="F", year_of_birth=1992)
barber = Barber(name="Bob", sex="M", year_of_birth=1987)

manicurist.do_job(neo)  # Теперь у Нео ногти длины 1 и, например, фиолетовые
barber.do_job(neo)      # Теперь у Нео волосы длины 9
barber.do_job(trinity)  # А тут программа падает с исключением ValueError...

Надо реализовать классы Human, Manicurist, Hairdresser, и Barber.

Задача 6 («Chemistry»)

Источник.

Далее постановка "специально" сильно упрощена 😅

Будем считать, что есть вещества, способные вступать в реакцию друг с другом. И есть индикаторы, по-разному действующие на каждое вещество.

Под веществами будем иметь в виду кислоту Acid, соль Salt, основание Base и воду Water. Индикаторы — фенолфталеин Phenolphthalein, лакмус Litmus и метилоранж MethylOrange. Индикатор определяется цветом (по умолчанию — фенолфталеин бесцветный, лакмус фиолетовый, а метилоранж оранжевый).

Пусть все возможные реакции между описанными веществами сводятся к следующему:

  • Кислота + Основание -> Соль + Вода
  • Соль + Кислота -> Соль + Кислота (новые)
  • Соль + Основание -> Соль + Основание (новые)

И с индикаторами:

  • Кислота + Фенолфталеин -> Фенолфталеин(бесцветный)
  • Кислота + Лакмус -> Лакмус(красный)
  • Кислота + Метилоранж -> Метилоранж(розовый)
  • Основание + Фенолфталеин -> Фенолфталеин(малиновый)
  • Основание + Лакмус -> Лакмус(синий)
  • Основание + Метилоранж -> Метилоранж(жёлтый)

Надо реализовать описанные классы. Операция реакции — через оператор +. В результате реакции получается кортеж из веществ. Если реакция не входит в число описанных выше (например, Соль + Соль), то надо бросать исключение TypeError.

Пример работы:

acid = Acid()
base = Base()

reaction_products = acid + base

print(reaction_products)  # (Соль, Вода)

salt = reaction_products[0]

print(base + salt)  # (Основание, Соль)

methyl_orange = MethylOrange()

print(methyl_orange)         # Метилоранж(оранжевый)
print(methyl_orange + acid)  # (Метилоранж(розовый),)

Задача 7 (Пирог)

Зима — это время борьбы за жизнь. По крайней мере, так считает Маша. Да, казалось бы, при чём тут зима, ведь ещё ноябрь. Однако не так давно уже были заморозки, с неба падал "дождеснег", а под ногами на улице был каток, перемежающийся оазисами из относительно глубоких ещё не промёрзших луж...

Но Маша не хочет поддаваться "мрачным" мыслям! Чтобы немного поднять настроение и себе, и коллегам по учёбе, она решила испечь яблочный пирог. У неё есть рецепт, для которого надо будет купить продукты, и есть несколько магазинов в окрестности. Помогите Маше: напишите программу, с помощью которой она могла бы сразу понять, сможет или нет купить в магазинах все необходимые ингредиенты, и если сможет, то в каком именно магазине (Маша хотела бы купить всё в одном месте) и на какую сумму выйдет вся покупка (хотя что такое деньги, когда речь идёт о том, чтобы привнести в жизнь немного красок).

Рецепт описан в файле recipe.txt: состав по пунктам и описание последовательности действий. Информация о магазинах приведена в файле shops.txt в следующем формате: название магазина, расстояние до него от дома Маши, и далее раздел о продуктах в этом магазине. Для каждого продукта известны: название, единица измерения (строка; штука, килограмм и т.п.), количество единиц в одной упаковке (флотовое число; предлагается считать, что фрукты тоже продаются в "упаковке" по одной штуке, то есть для фруктов известна как бы "средняя цена" за одну штуку, а не за килограмм), цена за упаковку в рублях (флотовое число), а также количество упаковок с продуктом в наличии в описываемом магазине (целое число).

В программе должны использоваться классы Рецепта и Магазина. Обход магазинов надо начинать в порядке от ближайшего к дальнему (если в ближнем уже можно купить все нужные для рецепта продукты, пусть и, возможно, по большой цене, то дальше не идём). Как только найден магазин, где можно всё купить, программа завершается и выводит ответ. Если же окажется так, что ни в одном магазине нельзя купить всего необходимого, то... но, нет, такого точно не будет — Маша обязательно всё купит и испечёт пирог!

Задача 8 (Снеговик)

Что нужно, чтобы слепить снеговика? Основное — это желание и готовность некоторое время позаниматься ерундой. И, конечно, нужен снег. Много снега. Не рыхлого, но немного влажного, который легко лепить. Далее, нужно скатать несколько комьев разного размера и в нужном порядке нанизать один на другой (маленький на большой). После этого снеговик можно считать в целом готовым (детали в виде веточек, морковки и ведра оставим за кадром).

Напишите программу – исполнитель, который лепит снеговика. Программа должна распознавать две команды:

  • катать — скатывает текущий ком снега, в результате его радиус увеличивается (на 2 см, если ком уже катали; если же он новый и ещё не начат, то сразу на 10 см);
  • положить — кладёт текущий ком снега на уже начатого снеговика, если последний положенный ком был больше размером; в противном случае — ком ложится в основание нового снеговика и далее программа будет лепить его.

Например:

# Снеговик из одного кома радиусом 10 + 2 = 12 см
катать
катать
положить

# Снеговик из двух комов: радиусом 12 см в основании и 10 см повыше
катать
катать
положить
катать
положить

# Два снеговика, первый из одного кома радиусом 10 см, второй из кома радиусом 12 см
катать
положить
катать
катать
положить

В файле snowman.txt описана последовательность действий, которая подаётся на вход исполнителю (в первой строчке указано общее число действий n, далее в n строках идут сами действия). Выведите на экран количество слеплённых снеговиков, высоту самого высокого снеговика, ширину самого широкого, и максимальное количество комьев в одном снеговике.

Как часть решения задачи предлагается реализовать классы: СнежныйКом, Снеговик и Исполнитель. Ком характеризуется радиусом, снеговик — составляющими его комьями (при этом важен порядок). Исполнитель должен уметь совершать описанные действия: скатать ком и положить его на снеговика.

Задача 9 (Букет)

Как-то вечером в цветочный магазин пришёл посетитель. Со вполне определённым запросом: он бы хотел составить букет из семи фиолетовых цветов одного вида, причём так, чтобы хотя бы пять из семи цветов были ещё не до конца распустившимися. Напишите программу, которая бы помогла флористу быстро понять, получится ли удовлетворить такой запрос (или лучше немного расспросить посетителя и попытаться предложить ему что-нибудь ещё). Если описанный букет составить можно (цветы есть в наличии), то надо вывести на экран общую стоимость букета (если есть несколько вариантов букетов, то самого дорогого). Если же ни одного букета составить нельзя, программа должна вывести на экран максимальное нечётное число ещё нераспустившихся фиолетовых цветов одного вида.

Информация об имеющихся в цветочном магазине цветах приведена в файле flowers.txt: для каждого цветка известно название (строка; роза, тюльпан и т.п.), цвет (строка), полностью ли распустился (булевское значение), и цена в рублях (целое число).

Помимо того, чтоб просто помочь флористу и посетителю магазина составить букет, программа также должна использовать "силу ООП". Предлагается реализовать два класса: Цветок и Букет. У цветка должны быть все описанные свойства, букет же характеризуется просто составляющими его цветами. Объекты цветов предлагается "научить" складываться через + и умножаться на число, при этом получается букет:

flower1 + flower2 + flower3  # букет из цветов flower1, flower2, flower3
flower * 3                   # букет из цветов flower, flower, flower

А букет предлагается научить красиво печататься в принте: результат принта для букета — символ , повторённый столько раз, сколько всего есть цветов в букете:

bouquet = flower1 + flower2 + flower3

print(bouquet)  # ⚘⚘⚘

Задача 10 (Pac-Man)

Предлагается с помощью ООП и pygame реализовать игру типа Пакмана. Можно сделать что-то совсем базовое в плане "геймплея", главное — чтобы было несколько взаимодействующих друг с другом классов (и чтобы всё-таки было играбельно).

Например, пусть есть один "активный кругляш" (Пакман), которым игрок может управлять с помощью стрелок клавиатуры (влево, вправо, вверх, вниз). И пусть на поле в случайном месте иногда появляется "статичный кругляш", который надо съесть (при этом съеденный кругляш пропадает с поля, а Пакман, например, увеличивается в размере).

(Описанный вариант игры — это даже, может, больше Змейка, а не Пакман, но не важно 🙂)

Задача 11* (Шахматы)

Напишите программу — генератор игры в шахматы. Игра начинается со стандартной расстановки (поле 8 x 8, есть чёрные и белые фигуры, с каждой стороны 8 пешек, 2 ладьи, 2 коня, 2 слона, король и королева). Далее "игроки" начинают совершать случайные (но при этом корректные) ходы. То есть обычный ход игрока заключается в случайном выборе фигуры (из тех, что могут сделать ход) и в совершении случайного (но допустимого) хода за выбранную фигуру. Ходом может быть либо просто перемещение своей фигуры по полю, либо "съедание" при этом фигуры противника, либо объявление шаха (в качестве более простого варианта игры предлагается такой, в котором на шах можно "не обращать внимания" и когда игра заканчивается просто случайным "съеданием" короля; в качестве более полного варианты игры стоит учесть и ситуацию с шахом: надо обязательно защитить короля — и такая игра уже должна заканчиваться матом или патом).

Предлагается реализовать классы для всех шахматных фигур и, возможно, ещё некоторые другие, если это будет иметь смысл (класс для поля? класс для игрока?)

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

Задача 12* (Сквозь снег)

День рождения Маши зимой, в конце декабря. И вчера вечером, перед сном, она подумала об авторе послания: знает ли он, когда у неё день рождения? готовится ли что-то сделать для неё в этот день? что-то подарить или, может, даже "раскрыться", перестать быть анонимом?..

С этими мыслями Маша и заснула, и ей приснился следующий сон.

Сегодня её день рождения.

Уже поздний вечер, на улице темно, горят фонари, дует ветер, идёт сильный снег, а "её аноним" бежит по улицам с букетом цветов, чтобы успеть до конца дня вручить цветы ей. Он примерно в курсе, где она живёт, но ещё никогда в том районе не был, поэтому точной дороги не знает и бежит "полунаугад", скорее веря, чем точно зная, что придёт куда нужно, к дому Маши. А тут ещё и снег летит в лицо, в глаза, видимость плохая, и порой он сомневается, что успеет вовремя...

Напишите с помощью ООП и pygame следующую игру по мотивам сна Маши. Есть поле со стенками: вертикальными и горизонтальными. Через верхнюю границу поля по всей длине сверху вниз летят "снежинки" (маленькие шарики). Они пролетают всё поле, но сквозь горизонтальные стенки не проходят. Игрок управляет персонажем ("активным кругляшом") размера больше снежинок, который в начале игры стоит перед горизонтальной стенкой. Управление (перемещение кругляша) осуществляется стрелками клавиатуры (влево, вправо, вверх, вниз). У игрока есть "букет" (несколько цветов, например семь). Ещё на поле есть "дом": это выделенная клетка поля, куда должен добраться игрок (принести букет). Сложность в том, что надо стараться избегать столкновений со снежинками. Три "пойманные" снежинки приводят к следующему: "замерзает" один цветок букета, а персонажу снег "застилает глаза", и он теряет ориентацию в пространстве. Потеря ориентации выражается в том, что дом "перемещается": исчезает со старого места и оказывается на новом (при этом далеко от игрока). Игра заканчивается, если персонаж добирается до дома с хотя бы одним цветком в запасе, или если все цветы замерзают (а персонаж окончательно теряет дорогу и так и остаётся блуждать один среди снежинок)...

Game start       After some tome

Эскиз предполагаемой игры. Желтый кружок — персонаж, синие кружки — снежинки (двигаются сверху вниз), серый квадрат — дом (место назачения), фиолетовые кружки снизу — цветы букета ("жизни"). Слева: начало игры (персонаж за стенкой). Справа: спустя несколько неаккуратных шагов (поймал три снежинки — один цветок исчез, а дом переместился).

P.S. Видимо, сложность игры будет очень сильно зависеть от характера падения снежинок...