- Дженерики
- Оператор индексирования
- Паттерн делегат
Требование! Каждое задание необходимо делать в отдельном проекте. Например, Task1.Quest1
, Task1.Quest2
, Task1.Quest3
и т.д. Если необходимо предыдущее задание для выполнение следующего, просто скопируйте код проекта в другой проект и разрабатывайте с ним. Для создания нового проекта в Rider нужно нажать ПКМ по Solution и выбрать Add->New Project с типом Console Application. Также необходимо использовать систему контроля версий Git
. Необходимо будет сделать не менее 4 коммитов(commit
), по 1 на каждое задание(не считая бонусных), а также первый коммит с заданием, дополнительные коммиты разрешены. После выполнения задания необходимо будет загрузить локальный репозиторий Git
в сетевое хранилище GitHub
, создав в нем новый публичный репозиторий, отключив добавление файла по-умолчанию README.md
. Вместо стандартного README.md
необходимо добавить в репозиторий первым коммитом с название Initial commit
файл с заданием.
Требуется описать класс, который представляет собой подобие револьвера.
- Структура может хранить до 6 элементов
- Вы можете добавить один элемент в ближайший свободный слот. При успешном добавлении возвращается true, иначе - false.
- Возможно добавления путем списка элементов. Функция принимает другую коллекцию, как ресурс, из которого добавляются все элементы в барабан. Если элементов в коллекции недостаточно, то заполняется структура револьвера настолько, насколько возможна. Если список пустой, метод возвращает false.
- Структура имеет указатель (pointer). После добавления он указывает на последний добавленный элемент. Вы можете получить настоящую позицию барабана, он вернет текущий элемент на курке.
- Вы можете удалять элементы одним за одним при помощи стрельбы("shoot"). Удаление начинается с элемента у pointer, затем pointer передвигается на следующий слот в барабане. Если слот пустой, функция возвращает null и передвигает pointer.
- Вы можете вызывать ("unload") для извлечения текущего элемента или всех разом. Функция возвращает извлеченный элемент либо список всех элементов.
- Вы можете двигать барабан путем "scroll", меняя позицию pointer на случайный элемент
- Добавьте метод, который возвращает количество элементов в структуре
- Переопределите стандартную функцию ToString, которая будет представлять информацию о классе и его элементах в виде
string
. Информация об элементах записывается, начиная с позиции элемента на курке (pointer). - У класса корректно работает оператор сравнения
==
. Переопределите его при помощи интерфейсаIEquatable<>
. Структуры эквивалентны, если имеют одинаковое сочетание элементов начиная с любой позиции, включая null. Пример сравнения представлен ниже. - Перегрузите для класса индексатор. Он будет возвращать для любого объекта класса при обращении по индексу элемент, который находится на данной позиции в барабане. Если индекс больше, чем число то происходит ошибка.
Проверьте результат: напишите программу, которая показывает, как работает структура
- Создайте объект, заполнив его при помощи конструктора максимальным количеством элементов. Напечатайте структура и указатель на позицию в барабане. Напечатанная структура должна начинать выводить с того же элемента, на котором находится
Pointer
. - Получите первый и последний элемент в барабане при помощи
индексатора
. Вызвав индексы соответствующих элементов. - Вызовите метод
Scroll
и напечатайте структуру - напечатанная структура должна начинаться с другого элемента (но он может быть равным по значению). Порядок между элементами должен сохраняться. - Удалите 4 элемента один за одним. Напечатайте структуру и сравните с предыдущим выводом. Измененный барабан должен начинаться с 5-ого элемента, за ним должен идти тот же элемент, что и до этого, затем 4 значения
null
. - Создайте коллекцию из 8 элементов того же типа, что и дженерик структуры. Добавьте эту коллекцию в револьвер и выведите сравнение старой и новой коллекции в структуру. Барабан должен заполниться полностью первыми 4 элементами из коллекции. Pointer устанавливается при каждом добавлении на заполненный элемент барабана.
- Вытащите все элементы структуры
Extract
. Напечатайте размер вытащенного списка и размер структуры (должно быт 6 и 0) - Добавьте 4 элемента
Supply
в коллекцию структуры. Размер барабана револьвера должен стать 4. - Создайте новую структуру с теми же элементами, как в полученном выше списке. Также необходимо сделать предварительный scroll. Далее сопоставьте при помощи оператора
==
эквивалентны ли эти структуры. Результат операции должен быть true.
Пример вывода программы
1. Adding elements
Structure: RevolverDrum<Int>
Objects: [3, 54, 7, 2, 56, 4]
Pointer: 3
2. Subscript
3, 4
3. Scroll
Structure: RevolverDrum<Int>
Objects: [7, 2, 56, 4, 3, 54]
Pointer: 7
3. Deletion
Structure: RevolverDrum<Int>
Objects: [3, 54, null, null, null, null]
Pointer: 3
4. Supply collection
Before:
Supply collection: [4, 6, 3, 22, 77, 43, 76, 5]
Structure: RevolverDrum<Int>
Objects: [3, 54, null, null, null, null]
Pointer: 3
After add operation performed:
Structure: RevolverDrum<Int>
Objects: [22, 54, 6, 4, 3, 54]
Pointer: 22
5. Extraction
The extracted list: [22, 54, 6, 4, 3, 54]
size: 6
Structure: RevolverDrum<Int>
Objects: [null, null, null, null, null, null]
Pointer: null
size: 0
6. Supply collection 2
Before:
Supply collection: [77, 43, 76, 5]
Structure: RevolverDrum<Int>
Objects: [null, null, null, null, null, null]
Pointer: null
After add operation performed:
Structure: RevolverDrum<Int>
Objects: [5, 76, 43, 77, null, null]
Pointer: 5
7. Equals
Structure: RevolverDrum<Int>
Objects: [null, 5, 76, 43, 77, null]
Pointer: null
Structure: RevolverDrum<Int>
Objects: [null, null, 5, 76, 43, 77]
Pointer: null
Result: equals
Требуется описать классы для работы с пулями в револьвере.
Пуля:
- Создайте интерфейс для пули (Bullet)
- Интерфейс должен иметь метод shoot()
- Также здесь нужно добавить поля для описания пули (холостая или заряженная)
- Для уникальности пули можете использовать класс
Guid
Типы пуль:
- Создайте Классы, описывающие пули по их калибру:
- TwentyTwo
- ThreeEighty
- FortyFive
- Каждый объект должен иметь свой метод
Shoot()
с выводом "Bang" и информации о калибре
Обновление структуры револьвера:
- Сделайте так, что револьвер работал только с типами
Bullet
. Вы не можете класть пули разных калибров в один барабан. - При вызове
Shoot()
соответствующий вызов должен происходить и у пули. Однако, если пуля холостая, то shoot у ее класса вызывать не нужно. - Если происходит выстрел при пустой ячейке, программа выводит "Click"
Представление соответствующей логики для структуры револьвера и пуль:
- Пуля может быть только в одном барабане револьверов. Если вы пытаетесь добавить пулю, которая уже есть в другом барабане,
Add
метод должен возвращать false и печатать, что произошла ошибка. Также, если вы добавляете коллекцию пуль, то подобная пуля должна быть проигнорирована, а остальные добавлены. - При выстреле из револьвера заряженной пулей должно выводится "A shoot one" или "A damp one", если пуля была холостой.
- Каждая пуля может быть использована для заряженного выстрела лишь раз. Если пуля холостая, она выпадет из револьвера, но выстрел не произойдет. Револьвер не должен вызывать метод стрельбы у пули, но печатает "Click", аналогично выстрелу из пустой ячейки.
Проверка результата: сделайте те же проверки, что и в предыдущем задании, но заполните револьвер пулями типа Bullet
.
- Проверьте, что заряженные пули стреляют, а холостые нет
- Попробуйте добавить пулю в разные револьверы. При первичном добавлении вернется true, вторичном - false.
- Попробуйте добавить пулю в две разные коллекции. И попробуйте добавить эти коллекции в два разных револьвера.
- Попробуйте выстрелить заряженной и холостой пулями. Должно быть выведено "A damp one" и "A shot one"
В данном задании требуется создать объект для профиля игрока и реализовать паттерн(не то же самое, что и ключевое слово delegate
) делегат
в виде присваивания объекта сервера классу игрока для поиска противника.
Профиль игрока:
- ID при помощи
Guid
- Никнейм
- Возраст
- Имя
- Револьвер
- Дата создания профиля в виде
string
- Статус (
ONLINE
-IN_PLAY
в игре,SEARCH
- в поиске,IDLE
в ожидании;OFFLINE
) - Ссылка, которая будет формироваться по примеру
http://gameserver.com/{id}-{nickname}
Игровой сервер Данный объект будет описывать логику взаимодействия между игроками. Объект должен содержать следующее:
- Адрес сервера
- Список игроков на сервере (список
Profile
)
Делегат сервера в профиле
При построении архитектуры в IOS приложении не редким является использование паттерна Делегат
для вызова части логики. Реализуем этот паттерн на примере вызова игроком поиска соперника.
Также создайте интерфейс PlayerAction
, который опишет возможные действия игрока при взаимодействии с сервером. В нашем случае там будет описана функция FindOpponent
. Класс сервера должен унаследовать интерфейс и реализовать эту функцию. Функция возвращает профиль найденного игрока.
Делегат сервера добавьте в виде переменной PlayerActionDelegate
класса PlayerAction
, который будет вызывать запрос поиска противника.
Проверка результата: создайте несколько объектов профилей с разным статусом и поместите их на сервер. Создайте свой профиль, который будет ONLINE и в режиме ожидания. Далее программа должна вызвать поиска оппонента и поменять статус игрока на SEARCH
. Функция должна вернуть оппонента противника, с новым статусом IN_PLAY
и поменять статус в профиле игрока.
Требуется реализовать различные классы оружия для игроков. В предыдущих заданиях вы уже сделали объекты револьвера и профиля игрока. Теперь добавим разнообразия для игры.
Оружие:
- название
- урон (от 0 до 100) от одного удара
- метод нанесения урона
Shoot()
.
Профиль игра теперь должен содержать оружие типа Weapon
.
Револьвер
Необходимо унаследовать класс револьвера от оружия, определяйте урон в зависимости от калибра пуля (больший калибр - больший урон). Создадим еще два типа оружия нож и винтовка.
Винтовка
Объект схож по функционалу с револьвером. Однако, винтовку необходимо каждый раз перезаряжать, добавляя пулю. Сделайте дополнительные классы для пулей винтовки. Поведение добавление пуль аналогично пулям для револьвера. Разделите пули револьвера и винтовки на два разных интерфейса. В револьвер только RevolverBallet
, в винтовку - RiffleBallet
. Также урон от винтовки зависит от типа пули.
Нож
- При вызове
Shoot()
программа выводитCrrr!
Проверка результата:
- создайте 3 оружие трех типов: револьвер, винтовка.
- Попробуйте добавить пули револьвера в магазин винтовки, и аналогично пули винтовки в револьвер. В обоих случаях функции должны вернуть
false
. - Выведите урон оружий с разными пулями. Чем больше калибр, тем больший урон должен наноситься пулей.
- При ударе ножом должно быть выведено
Crrr!
В объекте сервера необходимо описать логику боя:
- Метод
Fight()
, дополненный в интерфейсеPlayerAction
. Данный метод должен возвращать true, если победил игрок, false - победил противник. - Сам бой проходит со случайным порядком действия. Вы должны определять, кто бьет следующим случайным образом. На старте у игроков по 100 единиц здоровья. Каждый удар отнимает единицы здоровья в соответствии с уроном оружия. В тот момент, когда у одного из игроков становится 0 единиц и меньше, игра заканчивается. Победителем становится игрок c положительными единицами здоровья.
- При каждом ударе должно печататься текущее состояние боя в виде строки никнеймов бойцов и их здоровья, а также количество нанесенного урона. Например - "Player1 90, Player2 80 - Player 1 shoot by Knife 20".
Проверка результата:
- Создайте 2 игроков с различным типом оружия.
- Проверьте, что в ходе боя наносится соответствующее оружие количество урона и правильно отображается текущее состояние здоровья игроков.