LXF92:Mono
(→Классификация объектов: оформление) |
(оформление) |
||
(не показаны 3 промежуточные версии 1 участника) | |||
Строка 113: | Строка 113: | ||
'''Clubs''' – трефы, они же крести, '''Spades''' – пики, '''Player''' – игрок, англ.]: | '''Clubs''' – трефы, они же крести, '''Spades''' – пики, '''Player''' – игрок, англ.]: | ||
− | < | + | <source lang=csharp> |
using System; | using System; | ||
namespace Geno { | namespace Geno { | ||
Строка 135: | Строка 135: | ||
} | } | ||
} | } | ||
− | </ | + | </source> |
Ну да, знаю, здесь куча пустых методов, но они проясняют структуру программы. Заметили, что мне пришлось объявить все переменные | Ну да, знаю, здесь куча пустых методов, но они проясняют структуру программы. Заметили, что мне пришлось объявить все переменные | ||
Строка 161: | Строка 161: | ||
любого типа, то вам всегда придется сообщать ''Mono'', какой тип используется. Например: | любого типа, то вам всегда придется сообщать ''Mono'', какой тип используется. Например: | ||
− | < | + | <source lang=csharp> |
int i = 1; | int i = 1; | ||
ArrayList numbers = new ArrayList(); | ArrayList numbers = new ArrayList(); | ||
numbers.Add(i); | numbers.Add(i); | ||
int j = numbers[0]; | int j = numbers[0]; | ||
− | </ | + | </source> |
Здесь будет ошибка – ''Mono'' не сможет преобразовать '''numbers[0]''' | Здесь будет ошибка – ''Mono'' не сможет преобразовать '''numbers[0]''' | ||
Строка 172: | Строка 172: | ||
надо написать: | надо написать: | ||
− | < | + | <source lang=csharp> |
int j = (int)numbers[0]; | int j = (int)numbers[0]; | ||
− | </ | + | </source> |
Префикс '''(int)''' значит «обращаться с '''numbers[0]''' как с целым числом», и наш код будет компилироваться правильно. Новые версии ''C#'', включая поставляемую с Fedora Core 6, поддерживает новый способ | Префикс '''(int)''' значит «обращаться с '''numbers[0]''' как с целым числом», и наш код будет компилироваться правильно. Новые версии ''C#'', включая поставляемую с Fedora Core 6, поддерживает новый способ | ||
Строка 190: | Строка 190: | ||
Добавьте такие две строчки сразу под строкой '''class Geno''': | Добавьте такие две строчки сразу под строкой '''class Geno''': | ||
− | < | + | <source lang=csharp> |
List<Card> Cards = new List<Card>(); | List<Card> Cards = new List<Card>(); | ||
List<Player> Players = new List<Player>(); | List<Player> Players = new List<Player>(); | ||
− | </ | + | </source> |
Этот синтаксис может затуманить мозги, но по-простому он гласит | Этот синтаксис может затуманить мозги, но по-простому он гласит | ||
Строка 199: | Строка 199: | ||
список содержал переменные типа '''Players'''». Вы также должны добавить строку до переменной '''Score''' в классе '''Player''': | список содержал переменные типа '''Players'''». Вы также должны добавить строку до переменной '''Score''' в классе '''Player''': | ||
− | < | + | <source lang=csharp> |
public List<Card> Cards = new List<Card>(); | public List<Card> Cards = new List<Card>(); | ||
− | </ | + | </source> |
===Устанавливаем игру=== | ===Устанавливаем игру=== | ||
Строка 210: | Строка 210: | ||
вить карты будет перебрать в цикле все масти ('''Suits''), и для каждой масти посчитать от одного до 13 так, чтобы получить все от тузов до королей [туз считается единицей]. Добавив все карты и всех игроков, завершаем установку, вызывая метод '''ShuffleCards()''' для перетасовки карт. | вить карты будет перебрать в цикле все масти ('''Suits''), и для каждой масти посчитать от одного до 13 так, чтобы получить все от тузов до королей [туз считается единицей]. Добавив все карты и всех игроков, завершаем установку, вызывая метод '''ShuffleCards()''' для перетасовки карт. | ||
− | < | + | <source lang=csharp> |
foreach (Suits suit in Enum.GetValues(typeof(Suits))) { | foreach (Suits suit in Enum.GetValues(typeof(Suits))) { | ||
for (int i = 1; i < 14; ++i) { | for (int i = 1; i < 14; ++i) { | ||
Строка 225: | Строка 225: | ||
} | } | ||
ShuffleCards(); | ShuffleCards(); | ||
− | </ | + | </source> |
Вы видите, что надо вызвать просто '''Cards.Add(card)''', чтобы вставить карту в список из '''Cards'''; все очень просто. Метод '''ShuffleCards()''' пока ничего не делает, потому что он пустой. Нам необходимо пройтись по всему массиву '''Cards''', вытащить отдельные карты и поместить их обратно в произвольную позицию. Тут не обойтись без генератора | Вы видите, что надо вызвать просто '''Cards.Add(card)''', чтобы вставить карту в список из '''Cards'''; все очень просто. Метод '''ShuffleCards()''' пока ничего не делает, потому что он пустой. Нам необходимо пройтись по всему массиву '''Cards''', вытащить отдельные карты и поместить их обратно в произвольную позицию. Тут не обойтись без генератора | ||
случайных чисел – вставьте эту строку перед '''static void Main''': | случайных чисел – вставьте эту строку перед '''static void Main''': | ||
− | < | + | <source lang=csharp> |
Random Rand = new Random(); | Random Rand = new Random(); | ||
− | </ | + | </source> |
Теперь полная реализация '''ShuffleCards()''': | Теперь полная реализация '''ShuffleCards()''': | ||
− | < | + | <source lang=csharp> |
void ShuffleCards() { | void ShuffleCards() { | ||
for (int i = 0; i < Cards.Count; ++i) { | for (int i = 0; i < Cards.Count; ++i) { | ||
Строка 244: | Строка 244: | ||
} | } | ||
} | } | ||
− | </ | + | </source> |
Здесь показано несколько новых возможностей списков: у них есть | Здесь показано несколько новых возможностей списков: у них есть | ||
Строка 258: | Строка 258: | ||
выглядеть вот так: | выглядеть вот так: | ||
− | < | + | <source lang=csharp> |
int playernum = 0; | int playernum = 0; | ||
while (Cards.Count > 0) { | while (Cards.Count > 0) { | ||
Строка 270: | Строка 270: | ||
RemovePlayerPairs(i); | RemovePlayerPairs(i); | ||
} | } | ||
− | </ | + | </source> |
В последней части (от комментариев и ниже) уже начинается логи | В последней части (от комментариев и ниже) уже начинается логи | ||
Строка 281: | Строка 281: | ||
у него парные карты. Чтобы облегчить понимание, я разделил функцию на две, вот так: | у него парные карты. Чтобы облегчить понимание, я разделил функцию на две, вот так: | ||
− | < | + | <source lang=csharp> |
void RemovePlayerPairs(int player) { | void RemovePlayerPairs(int player) { | ||
while (TryPairRemove(player)) { | while (TryPairRemove(player)) { | ||
Строка 287: | Строка 287: | ||
} | } | ||
} | } | ||
− | </ | + | </source> |
Итак, номер игрока поступает в функцию и передается методу | Итак, номер игрока поступает в функцию и передается методу | ||
Строка 298: | Строка 298: | ||
удалить пару и вернуть '''true'''. | удалить пару и вернуть '''true'''. | ||
− | < | + | <source lang=csharp> |
bool TryPairRemove(int player) { | bool TryPairRemove(int player) { | ||
Card card1; | Card card1; | ||
Строка 319: | Строка 319: | ||
return false; | return false; | ||
} | } | ||
− | </ | + | </source> |
Некоторые комментарии по коду: | Некоторые комментарии по коду: | ||
Строка 358: | Строка 358: | ||
|Ширина=200px}} | |Ширина=200px}} | ||
− | < | + | <source lang=csharp> |
bool finished = false; | bool finished = false; | ||
while (!finished) { | while (!finished) { | ||
Строка 368: | Строка 368: | ||
continue; | continue; | ||
} | } | ||
− | </ | + | </source> |
Здесь отслеживается число игроков, оставшихся в игре. Если это | Здесь отслеживается число игроков, оставшихся в игре. Если это | ||
Строка 374: | Строка 374: | ||
цикл просто обрабатывает каждого игрока. | цикл просто обрабатывает каждого игрока. | ||
− | < | + | <source lang=csharp> |
int playertouse = -1; | int playertouse = -1; | ||
for (int j = i + 1; j < Players.Count; ++j) { | for (int j = i + 1; j < Players.Count; ++j) { | ||
Строка 390: | Строка 390: | ||
} | } | ||
} | } | ||
− | </ | + | </source> |
Этот блок ищет игрока, у которого нужно вытянуть карту: сперва | Этот блок ищет игрока, у которого нужно вытянуть карту: сперва | ||
Строка 396: | Строка 396: | ||
автоматически пропускаются. | автоматически пропускаются. | ||
− | < | + | <source lang=csharp> |
if (playertouse == i) { | if (playertouse == i) { | ||
finished = true; | finished = true; | ||
Строка 409: | Строка 409: | ||
} | } | ||
} | } | ||
− | </ | + | </source> |
Теперь начинается самое интересное: если мы добрались сами | Теперь начинается самое интересное: если мы добрались сами | ||
Строка 416: | Строка 416: | ||
'''RemovePlayerPairs()''', для сброса подходящей пары. | '''RemovePlayerPairs()''', для сброса подходящей пары. | ||
− | < | + | <source lang=csharp> |
if (playersleft == 1) finished = true; | if (playersleft == 1) finished = true; | ||
} | } | ||
PrintResults(); | PrintResults(); | ||
− | </ | + | </source> |
Наконец, если игроков не осталось, завершаем цикл. Игра закончена, и '''PrintResult()''' выдает сообщение: | Наконец, если игроков не осталось, завершаем цикл. Игра закончена, и '''PrintResult()''' выдает сообщение: | ||
− | < | + | <source lang=csharp> |
void PrintResults() { | void PrintResults() { | ||
Console.WriteLine(“”); | Console.WriteLine(“”); | ||
Строка 434: | Строка 434: | ||
} | } | ||
} | } | ||
− | </ | + | </source> |
Если вы запустите программу, то увидите четырех компьютерных | Если вы запустите программу, то увидите четырех компьютерных |
Текущая версия на 11:17, 24 ноября 2008
|
|
|
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
- Mono-Мания Программирование на современной платформе для новичков
Содержание |
[править] Mono: Объекты и обобщенные типы
- Объектно-ориентированное программирование кое-кого пугает больше, чем школьников прививки, но Пол Хадсон собирается обойтись без боли.
В теории, теория и практика совпадают, но на практике так бывает редко. Вот почему в наших уроках обучение строится на процессе выполнения: если вы читали этот учебник с самого начала, то уже сделали пять полноценных приложений, решающих реальные задачи. На данном уроке я хочу отойти от принятой формулы и обсудить довольно сложную теорию программирования: объектно-ориентированное программирование (ООП) и обобщенные типы.
Это не штуки, из которых можно делать свои приложения, а просто методы, которые пригодятся вам при программировании на Mono. Коль скоро вы это поняли, я покажу вам, как реализовать карточную игру с помощью названных двух методов.
[править] Классификация объектов
ООП позволяет определять предметы в вашем программном коде и даже придавать им желаемое поведение. Вы уже использовали ООП, только не догадывались об этом. Создайте новый проект с именем Geno (еще один редкий персонаж Nintendo – уж простите!), и вы уви- дите, что MonoDevelop напишет код по умолчанию:
class MainClass { public static void Main(string[] args) { Console.WriteLine(“Hello World!”); } }
Здесь применяется ООП, и программа отлично работает, даже если вы не понимаете, что это значит (да и знать не хотите). Но теперь знайте: класс – это определение предмета, а объект – это экземпляр предмета. Ясно как ночь? Так вот: на вопросы «Какого цвета машина?», «Какая длина у машины?» или «Сколько у машины передач?» ответ будет «это зависит от»: что такое машина, представляют все, но каждая машина индивидуальна.
В терминах ООП, «машина» является классом. Но «машину вообще» увидеть нельзя: это абстрактное понятие. На самом деле мы видим «Форды», «Хонды» и так далее, то есть физические реализации класса «машина». Итак: машина, находящаяся на шоссе, это объект класса «машина». У нее есть цвет, длина, и вы знаете, сколько у нее передач, но это просто переменные свойства класса «машина». Другие машины, даже той марки, что и ваша, могут сильно отличаться; но все они машины.
Если для вас это все еще пустой звук, подождите: вы все поймете из кода! А пока MonoDevelop определил для нас класс MainClass, содержащий метод public static void Main(), который мы все время используем. Два странных слова – public и static – относятся к ООП.
[править] Объект Geno
Измените MainClass на Geno, имя нашего проекта. Теперь замените строку Console.WriteLine() на следующую:
Geno game = new Geno();
Этот код создает объект класса Geno и присваивает его переменной game. Что представляет собой класс Geno? В данный момент он содержит только Main() и больше ничего – это просто пустая переменная. Но она рождает интересный вопрос: строка находится внутри метода Main(), который находится внутри класса Geno. Как может Geno создать сам себя? Или – основной вопрос философии: что появилось раньше, класс Geno или метод Main()?
Тут на помощь приходит слово ‘static’ – статический. Метод Main(), если вы помните, помечен как public static void, и на то есть причина: статические методы могут вызываться без экземпляра класса. Фактически они привязывают метод к классу, просто в организационных целях. Например, если в нашем классе был метод СменитьПередачу(), его применение не имело бы смысла без конкретного экземпляра машины, так как в противном случае, какую передачу надо менять? А как насчет вычисления тормозного пути машины, мчащейся со скоростью 100 км/ч? К машинам это имеет отношение, ноясно, что для этого не требуется реальный объект машины.
Таким образом, статический метод Main() может вызываться без существования класса Geno, и мы используем его для создания объекта Geno так, чтобы можно было играть в карточную игру. Объект Geno будет контролировать все аспекты игры, поэтому других объектов нам не понадобится. Но, ради интереса, мы добавим еще два класса: один будет отвечать за игроков, другой за карты. Логика отдается на откуп объекту Geno, так что классы игрока и карт предназначены просто для хранения данных.
Есть еще кое-что, что вам надо знать, прежде чем писать код. Иногда нужно, чтобы переменная принимала значение только из определенного набора. Например, набор данных для дней недели – воскресенье, понедельник, вторник и т.д. Для карточной игры требуется, чтобы каждая карта была определенной масти: червы, бубны, трефы или пики. C# позволяет определить масти карт как перечисление:
public enum Suits { Hearts, Diamonds, Clubs, Spades };
[править] Описываем игру
Запрограммируем детскую игру: она, возможно, знакома вам как «Дама червей». Из карточной колоды извлекается одна дама (бубен), остается 51 карта. Карты сдаются всем игрокам, втемную. Игроки смотрят на свои карты и сбрасывают пары карт одинакового достоинства: например, если у игрока есть две десятки, то он кладет эти две десятки на стол. Дама червей не может быть использована как парная карта; игрок, которому она досталась, должен ее сохранить.
После того, как все игроки выкинули свои пары, первый игрок поворачивается к игроку справа и втемную забирает у него произвольную карту. Если в результате у игрока образовались парные карты, то он может их сбросить. Игра продолжается, и второй игрок поворачивается к игроку справа и вынимает карту – и так далее. В конечном счете, каждая карта должна найти себе пару, за исключением дамы червей, а игрок, у которого она на руках, проигрывает. [порусски эта игра называется «Акулина» или «Акулька», но непарная дама – пиковая, – прим.ред.]
Нам надо предусмотреть следующие функции:
- Play() Эта функция начинает игру, после проведения необходимых настроек.
- ShuffleCards() Перетасовать колоду (рандомизировать порядок карт).
- RemovePlayerPairs() Поиск и удаление подходящей пары карты у игрока.
- PrintResult() Печать результатов игры (у кого осталась червонная дама).
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Также потребуется определить классы Player и Card, которые будут содержать информацию. Вот скелет будущего кода [для большей ясности: Suit – масть, Card – карта, Hearts – черви, Diamonds – бубны, Clubs – трефы, они же крести, Spades – пики, Player – игрок, англ.]:
using System; namespace Geno { enum Suits { Hearts, Diamonds, Clubs, Spades }; class Card { public int Val; public Suits Suit; } class Player { public int Score; } class Geno { static void Main(string[] args) { Geno game = new Geno(); game.Play(); } void Play() { } void ShuffleCards() { } void RemovePlayerPairs(int player) { } void PrintResults() { } } }
Ну да, знаю, здесь куча пустых методов, но они проясняют структуру программы. Заметили, что мне пришлось объявить все переменные внутри классов Player и Card как public? Это потому, что переменные внутри объекта доступны только внутри самого объекта, чтобы внешние части кода их не затрагивали. Но так как у нас довольно простая программа, класс Geno будет делать большую часть работы и использовать классы Player и Card просто для хранения значений. То, что эти переменные стали public, значит, что класс Geno может их читать и записывать [в серьезных программах так делать не рекомендуется – вместо этого следует определить методы, обеспечивающие доступ извне к закрытым переменным, – прим.ред.].
[править] Введение в обобщенные типы
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
У нас есть класс Card, то есть мы можем определить значение карты (от 1 до 13) и ее масть. Но мы еще не создали сам объект «карты» и не знаем, где их хранить. Здесь приходят на помощь массивы: они позволяют хранить множество объектов в одной переменной. У Mono есть огромное количество типов массивов, но долгое время наиболее используемым был ArrayList. Он позволяет хранить в массиве любой тип объекта и обращаться к нему просто по индексу. Но здесь есть проблема: у каждой переменной в C# есть тип, будь то integer, string, Suit или любой другой. Так как ArrayList может содержать переменную любого типа, то вам всегда придется сообщать Mono, какой тип используется. Например:
int i = 1; ArrayList numbers = new ArrayList(); numbers.Add(i); int j = numbers[0];
Здесь будет ошибка – Mono не сможет преобразовать numbers[0] в integer, даже если мы знаем, что оно уже типа integer. Вместо этого надо написать:
int j = (int)numbers[0];
Префикс (int) значит «обращаться с numbers[0] как с целым числом», и наш код будет компилироваться правильно. Новые версии C#, включая поставляемую с Fedora Core 6, поддерживает новый способ программирования, известный как обобщенные типы (generics). И если вы когда-либо раньше использовали С++, то знакомы с термином «шаблон», а это почти тоже самое – только на вид гораздо легче!
Обобщенные типы – это произвольные массивы, которые принимают только один тип переменных. Вам уже не надо приписывать (int), чтобы вытаскивать целые числа из обобщенного списка – туда так и так можно помещать только целые числа. В Geno обобщенные типы будут использоваться для двух вещей: хранения карт и хранения игроков. У каждого игрока будет свой собственный список карт, так как карты из колоды раздаются именно игрокам.
Добавьте такие две строчки сразу под строкой class Geno:
List<Card> Cards = new List<Card>(); List<Player> Players = new List<Player>();
Этот синтаксис может затуманить мозги, но по-простому он гласит «Хочу, чтобы один список содержал переменные типа Card, а второй список содержал переменные типа Players». Вы также должны добавить строку до переменной Score в классе Player:
public List<Card> Cards = new List<Card>();
[править] Устанавливаем игру
Оба наших списка Players и Cards пусты, поэтому первым заданием будет поместить 51 карту в колоду (помните, что мы убрали бубновую даму) и разместить несколько игроков. Самым простым способом вста- вить карты будет перебрать в цикле все масти ('Suits), и для каждой масти посчитать от одного до 13 так, чтобы получить все от тузов до королей [туз считается единицей]. Добавив все карты и всех игроков, завершаем установку, вызывая метод ShuffleCards() для перетасовки карт.
foreach (Suits suit in Enum.GetValues(typeof(Suits))) { for (int i = 1; i < 14; ++i) { Card card = new Card(); card.Val = i; card.Suit = suit; if (card.Val == 12 && card.Suit == Suits.Diamonds) continue; Cards.Add(card); } } for (int i = 0; i < 4; ++i) { Player player = new Player(); Players.Add(player); } ShuffleCards();
Вы видите, что надо вызвать просто Cards.Add(card), чтобы вставить карту в список из Cards; все очень просто. Метод ShuffleCards() пока ничего не делает, потому что он пустой. Нам необходимо пройтись по всему массиву Cards, вытащить отдельные карты и поместить их обратно в произвольную позицию. Тут не обойтись без генератора случайных чисел – вставьте эту строку перед static void Main:
Random Rand = new Random();
Теперь полная реализация ShuffleCards():
void ShuffleCards() { for (int i = 0; i < Cards.Count; ++i) { Card tmp = Cards[i]; Cards.RemoveAt(i); Cards.Insert(Rand.Next(0, Cards.Count), tmp); } }
Здесь показано несколько новых возможностей списков: у них есть свойство Count, которое возвращает число содержащихся в них элементов; они содержат метод RemoveAt(), который удаляет элемент в указанной позиции; и у них есть метод Insert(), который вставляет элемент в указанную позицию. Номер позиции определяется переменной Rand, которая может генерировать число между 0 и Crads.Count (количество карт в колоде).
[править] Раздаем карты
Наша колода заполнена и стасована. Осталось сдать ее игрокам. Чтобы это сделать, будем давать им карты, пока колода не кончится. Это зна чит, что нам надо начать с игрока 0 (в C# списки начинаются с 0), сдать карту, перейти к игроку 1, сдать карту и так далее, пока не закончатся игроки; потом перейти снова к игроку 0. В коде этот алгоритм будет выглядеть вот так:
int playernum = 0; while (Cards.Count > 0) { Players[playernum].Cards.Add(Cards[0]); Cards.RemoveAt(0); ++playernum; if (playernum == Players.Count) playernum = 0; } // удалять начальные пары for (int i = 0; i < Players.Count; ++i) { RemovePlayerPairs(i); }
В последней части (от комментариев и ниже) уже начинается логи ка игры: каждый игрок удаляет пары карт, которые оказались у него в начале игры.
[править] Пишем логику
Метод RemovePlayerPairs() принимает на вход номер игрока и удаляет у него парные карты. Чтобы облегчить понимание, я разделил функцию на две, вот так:
void RemovePlayerPairs(int player) { while (TryPairRemove(player)) { ++Players[player].Score; } }
Итак, номер игрока поступает в функцию и передается методу TryPairRemove(). Если этот метод вернул true, значит, была найдена пара; затем он вызывается снова. В конце концов будут найдены все пары, и цикл завершит свою работу.
Метод TryPairRemove() немного сложноват, так как ему надо у каждого игрока взять карту, перебрать остальные его карты на предмет совпадения, и если в паре ни одна из карт не является дамой червей удалить пару и вернуть true.
bool TryPairRemove(int player) { Card card1; Card card2; Player thisplayer = Players[player]; for (int i = 0; i < thisplayer.Cards.Count; ++i) { card1 = thisplayer.Cards[i]; if (card1.Suit == Suits.Hearts && card1.Val == 12) continue; for (int j = i + 1; j < thisplayer.Cards.Count; ++j) { card2 = thisplayer.Cards[j]; if (card2.Suit == Suits.Hearts && card2.Val == 12) continue; if (card1.Val == card2.Val) { thisplayer.Cards.RemoveAt(j); thisplayer.Cards.RemoveAt(i); Console.WriteLine(“Player “ + (player + 1) + “ plays “ + CardName(card1) + “ and “ + CardName(card2)); return true; } } } return false; }
Некоторые комментарии по коду:
- 1 j начинается с i+1: среди проверенных карт совпадений нет.
- 2 Проверка совпадения с дамой червей делается и для card1, и для card2.
- 3 Если найдено совпадение, сначала удаляется j, затем i. Удаление элемента из списка заставляет сдвигаться все элементы массива, чтобы закрыть пробел, поэтому первым надо удалять элемент с более высоким индексом.
- 4 Метод CardName() будет описан далее.
Да, это солидный кусок кода, ведь мы должны дважды перебрать карты игрока. Метод CardName() очень прост и выдает названия карт, я не буду приводить его здесь – можете обратиться к исходному коду на диске.
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
[править] Последний рывок
Оставшийся код обрабатывает основной игровой цикл: игроки выбирают карты и пытаются найти пары. Самой сложной частью является выбор игрока, у которого надо вытащить карту: код должен начать искать игрока «справа» от нас (то есть его номер должен быть больше нашего), но если он никого не находит, то начинает смотреть с начала списка. Если он вернулся обратно, значит, игра закончилась. Если найден подходящий игрок, у него выбирается карта, возможно, сбрасываются новые пары, и игра продолжается.
Этот код должен следовать до конца метода Play(). Он длинный, но не такой сложный, если разбить его на части вот так:
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
bool finished = false; while (!finished) { int playersleft = Players.Count; for (int i = 0; i < Players.Count; ++i) { Player player = Players[i]; if (player.Cards.Count == 0) { --playersleft; continue; }
Здесь отслеживается число игроков, оставшихся в игре. Если это значение равно 1, то надо выходить; займемся этим позже. Сейчас цикл просто обрабатывает каждого игрока.
int playertouse = -1; for (int j = i + 1; j < Players.Count; ++j) { if (Players[j].Cards.Count > 0) { playertouse = j; break; } } if (playertouse == -1) { for (int j = 0; j < Players.Count; ++j) { if (Players[j].Cards.Count > 0) { playertouse = j; break; } } }
Этот блок ищет игрока, у которого нужно вытянуть карту: сперва над текущей позицией, потом с начала. Игроки, у которых нет карт, автоматически пропускаются.
if (playertouse == i) { finished = true; break; } else { int cardtochoose = Rand.Next(0, Players[playertouse].Cards. Count); Players[i].Cards.Add(Players[playertouse]. Cards[cardtochoose]); Players[playertouse].Cards.RemoveAt(cardtochoose); RemovePlayerPairs(i); } }
Теперь начинается самое интересное: если мы добрались сами до себя, значит, нет игроков, у которых можно взять карту. В противном случае, берем произвольную карту и вызываем метод RemovePlayerPairs(), для сброса подходящей пары.
if (playersleft == 1) finished = true; } PrintResults();
Наконец, если игроков не осталось, завершаем цикл. Игра закончена, и PrintResult() выдает сообщение:
void PrintResults() { Console.WriteLine(“”); for (int i = 0; i < Players.Count; ++i) { if (Players[i].Cards.Count > 0) { Console.WriteLine(“У игрока “ + (i + 1) + “ осталась дама червей!”); break; } } }
Если вы запустите программу, то увидите четырех компьютерных игроков, играющих около секунды. Теперь у вас есть понимание о классах и объектах, и вы можете извлечь преимущества обобщенных типов для хранения ваших объектов. Вы также узнали, как сделать несложную карточную игру – полпути к разработке покера или любой другой игры. LXF