/Csharp-Task1

Csharp developing

Primary LanguageC#

Привет

Темы

  • Дженерики
  • Оператор индексирования
  • Паттерн делегат

Проект: утилиты для создания игр

Задания

Требование! Каждое задание необходимо делать в отдельном проекте. Например, 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 файл с заданием.

Задание 1. Мир дикого запада

Требуется описать класс, который представляет собой подобие револьвера.

  • Структура может хранить до 6 элементов
  • Вы можете добавить один элемент в ближайший свободный слот. При успешном добавлении возвращается true, иначе - false.
  • Возможно добавления путем списка элементов. Функция принимает другую коллекцию, как ресурс, из которого добавляются все элементы в барабан. Если элементов в коллекции недостаточно, то заполняется структура револьвера настолько, насколько возможна. Если список пустой, метод возвращает false.
  • Структура имеет указатель (pointer). После добавления он указывает на последний добавленный элемент. Вы можете получить настоящую позицию барабана, он вернет текущий элемент на курке.
  • Вы можете удалять элементы одним за одним при помощи стрельбы("shoot"). Удаление начинается с элемента у pointer, затем pointer передвигается на следующий слот в барабане. Если слот пустой, функция возвращает null и передвигает pointer.
  • Вы можете вызывать ("unload") для извлечения текущего элемента или всех разом. Функция возвращает извлеченный элемент либо список всех элементов.
  • Вы можете двигать барабан путем "scroll", меняя позицию pointer на случайный элемент
  • Добавьте метод, который возвращает количество элементов в структуре
  • Переопределите стандартную функцию ToString, которая будет представлять информацию о классе и его элементах в виде string. Информация об элементах записывается, начиная с позиции элемента на курке (pointer).
  • У класса корректно работает оператор сравнения ==. Переопределите его при помощи интерфейса IEquatable<>. Структуры эквивалентны, если имеют одинаковое сочетание элементов начиная с любой позиции, включая null. Пример сравнения представлен ниже.
  • Перегрузите для класса индексатор. Он будет возвращать для любого объекта класса при обращении по индексу элемент, который находится на данной позиции в барабане. Если индекс больше, чем число то происходит ошибка.

Проверьте результат: напишите программу, которая показывает, как работает структура

  1. Создайте объект, заполнив его при помощи конструктора максимальным количеством элементов. Напечатайте структура и указатель на позицию в барабане. Напечатанная структура должна начинать выводить с того же элемента, на котором находится Pointer.
  2. Получите первый и последний элемент в барабане при помощи индексатора. Вызвав индексы соответствующих элементов.
  3. Вызовите метод Scroll и напечатайте структуру - напечатанная структура должна начинаться с другого элемента (но он может быть равным по значению). Порядок между элементами должен сохраняться.
  4. Удалите 4 элемента один за одним. Напечатайте структуру и сравните с предыдущим выводом. Измененный барабан должен начинаться с 5-ого элемента, за ним должен идти тот же элемент, что и до этого, затем 4 значения null.
  5. Создайте коллекцию из 8 элементов того же типа, что и дженерик структуры. Добавьте эту коллекцию в револьвер и выведите сравнение старой и новой коллекции в структуру. Барабан должен заполниться полностью первыми 4 элементами из коллекции. Pointer устанавливается при каждом добавлении на заполненный элемент барабана.
  6. Вытащите все элементы структуры Extract. Напечатайте размер вытащенного списка и размер структуры (должно быт 6 и 0)
  7. Добавьте 4 элемента Supply в коллекцию структуры. Размер барабана револьвера должен стать 4.
  8. Создайте новую структуру с теми же элементами, как в полученном выше списке. Также необходимо сделать предварительный 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

Задание 2. Пули

Требуется описать классы для работы с пулями в револьвере.

Пуля:

  • Создайте интерфейс для пули (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"

Задание 3. Профиль игрока

В данном задании требуется создать объект для профиля игрока и реализовать паттерн(не то же самое, что и ключевое слово 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 и поменять статус в профиле игрока.

Бонусное задание 4. Виды вооружений

Требуется реализовать различные классы оружия для игроков. В предыдущих заданиях вы уже сделали объекты револьвера и профиля игрока. Теперь добавим разнообразия для игры.

Оружие:

  • название
  • урон (от 0 до 100) от одного удара
  • метод нанесения урона Shoot().

Профиль игра теперь должен содержать оружие типа Weapon.

Револьвер Необходимо унаследовать класс револьвера от оружия, определяйте урон в зависимости от калибра пуля (больший калибр - больший урон). Создадим еще два типа оружия нож и винтовка. Винтовка Объект схож по функционалу с револьвером. Однако, винтовку необходимо каждый раз перезаряжать, добавляя пулю. Сделайте дополнительные классы для пулей винтовки. Поведение добавление пуль аналогично пулям для револьвера. Разделите пули револьвера и винтовки на два разных интерфейса. В револьвер только RevolverBallet, в винтовку - RiffleBallet. Также урон от винтовки зависит от типа пули. Нож

  • При вызове Shoot() программа выводит Crrr!

Проверка результата:

  • создайте 3 оружие трех типов: револьвер, винтовка.
  • Попробуйте добавить пули револьвера в магазин винтовки, и аналогично пули винтовки в револьвер. В обоих случаях функции должны вернуть false.
  • Выведите урон оружий с разными пулями. Чем больше калибр, тем больший урон должен наноситься пулей.
  • При ударе ножом должно быть выведено Crrr!

Бонусное задание 5. Хороший, плохой, злой

В объекте сервера необходимо описать логику боя:

  • Метод Fight(), дополненный в интерфейсе PlayerAction. Данный метод должен возвращать true, если победил игрок, false - победил противник.
  • Сам бой проходит со случайным порядком действия. Вы должны определять, кто бьет следующим случайным образом. На старте у игроков по 100 единиц здоровья. Каждый удар отнимает единицы здоровья в соответствии с уроном оружия. В тот момент, когда у одного из игроков становится 0 единиц и меньше, игра заканчивается. Победителем становится игрок c положительными единицами здоровья.
  • При каждом ударе должно печататься текущее состояние боя в виде строки никнеймов бойцов и их здоровья, а также количество нанесенного урона. Например - "Player1 90, Player2 80 - Player 1 shoot by Knife 20".

Проверка результата:

  • Создайте 2 игроков с различным типом оружия.
  • Проверьте, что в ходе боя наносится соответствующее оружие количество урона и правильно отображается текущее состояние здоровья игроков.