Игральные карты — пасьянс

339
20 июля 2018, 18:30

Пишу консольную программку на c#, задание такое:
Создать класс колоду карт. Создать конструкторы колоды должны инициализировать колоду как случайным образом, так и в определенном порядке. Создать производный класс от колоды - пасьянс, в котором выбираются по три карты и, если две крайние одного цвета, то их выбрасывают. Всю колоду проходят три раза.

Сделал класс колоду, в нем описал методы вывода карт по порядку и с перетасовкой, осталось реализовать второй класс самой игры. Собственно вопросы: 1)Есть массив

public string[] cardArray = new string[36] с картами, и массивы черных и красных карт
public string[] BlackCards = { "6П", "6К", "7П", "7К", "8П", "8К", "9П", "9К", "10П", "10К", "ВП", "ВК", "ДП", "ДК", "КП", "КК", "ТП", "ТК" };//карты чёрной масти
public string[] RedCards = { "6Ч", "6Б", "7Ч", "7Б", "8Ч", "8Б", "9Ч", "9Б", "10Ч", "10Б", "ВЧ", "ВБ", "ДЧ", "ДБ", "КЧ", "КБ", "ТЧ", "ТБ" };//карты красной масти

Каким образом можно перебирать карты и в зависимости от того какие карты(олинаковые или нет),удалять или оставлять карты в массиве? Пока сделал проверку вот так, проверяю на вхождение крайних карт и если обе одного цвета то удаляю, а вместо 2 удаленных встают следующие 2 карты из колоды и т.д(или не нужно так делать?а просто тупо проверять каждые 3 карты, тогда я вообще ничего не понял))):

left = cardArray[0];
center = cardArray[1];
right = cardArray[2];
Console.WriteLine(left + " " + center + " " + right);// вывести 3 карты
for (int i = 0; i < BlackCards.Length; i++)
{
    for (int j = 0; j < RedCards.Length; j++)
    {
        if ((right == BlackCards[i] && left == BlackCards[j]) || (right == RedCards[i] && left == RedCards[j]))
        {
            cardArray = cardArray.Where(w => w != left && w != right).ToArray();
            tmp = cardArray[0];
            cardArray[0] = cardArray[1];
            cardArray[1] = tmp;
            drop = true;
        }
    }
}

Не понимаю что надо делать в тех случаях если крайние карты не одинакового цвета? Брать следующую тройку и ложить поверху предыдущих и проверять?и т.д? И как это проходить колоду 3 раза?

Answer 1

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

Создадим сначала пару перечислений

public enum SuitCard
{
    Spades, // пики (чёрн.масть)
    Clubs,  // трефы (чёрн.масть)
    Hearts, // червы (красн.масть)
    Diamonds, // бубны (красн.масть)
    Dummy, // карта заглушка
}
public enum RankCard
{
    [Display(Name = "Туз")]
    Ace,
    [Display(Name = "2")]
    Two,
    [Display(Name = "3")]
    Three,
    [Display(Name = "4")]
    Four,
    [Display(Name = "5")]
    Five,
    [Display(Name = "6")]
    Six,
    [Display(Name = "7")]
    Seven,
    [Display(Name = "8")]
    Eight,
    [Display(Name = "9")]
    Nine,
    [Display(Name = "10")]
    Ten,
    [Display(Name = "Валет")]
    Jack,
    [Display(Name = "Дама")]
    Queen,
    [Display(Name = "Король")]
    King,
    [Display(Name = "")]
    Dummy,
}

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

public class DisplayAttribute : Attribute
{
    public string Name { get; set; }
    //ctor
    public DisplayAttribute()
    {
    }
}
public static class EnumDisplayExtensions 
{
    public static string GetDisplayName(this Enum enumValue)
    {
        //тип класса атрибута
        var attributeType = typeof(DisplayAttribute);
        //находим поле enum к которому относится данные значение
        FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());
        //атрибуты привязанные к этому значению enum
        var attributes = fi.GetCustomAttributes(attributeType, false)
                           .Cast<DisplayAttribute>()
                           .ToList();
        List<string> names = new List<string>();
        foreach (var attribute in attributes)
        {
            //извлекаем значение свойства у атрибута
            string name = attribute.Name;
            names.Add(name);
        }
        return String.Join("", names);
    }
}

Начнем с класса Карты. Его задача хранить в своих свойствах карту и отображать ее на консоль, с использованием юникод значков.

public class Card
{
    public static int NumberRanks => Enum.GetValues(typeof(RankCard)).Length - 1;
    public static int NumberSuits => Enum.GetValues(typeof(SuitCard)).Length - 1;
    public ConsoleColor Color { get; private set; }
    public RankCard Rank { get; private set; }
    public SuitCard Suit { get; private set; }
    public char UnicodeSign { get; private set; }
    //ctor
    public Card(RankCard rankOfCard, SuitCard suitOfCard)
    {
        //назначаем цвет
        if (suitOfCard == SuitCard.Hearts || suitOfCard == SuitCard.Diamonds)
            Color = ConsoleColor.Red;
        else
            Color = ConsoleColor.White;
        //масть
        Rank = rankOfCard;
        Suit = suitOfCard;
        //назначаем символ карты
        UnicodeSign = SetUnicodeSign();
    }
    private char SetUnicodeSign()
    {
        switch (Suit)
        {
            case SuitCard.Spades:
                return '\u2660';
            case SuitCard.Clubs:
                return '\u2663';
            case SuitCard.Hearts:
                return '\u2665';
            case SuitCard.Diamonds:
                return '\u2666';
            case SuitCard.Dummy:
                return '-';
            default:
                return '-';
        }
    }
    /// <summary>
    /// Отображение карты со значком масти
    /// </summary>
    public void ShowCard()
    {
        //для правильного отображения значков мастей 
        Console.OutputEncoding = Encoding.Unicode;
        //цвет текста будет соответствовать цвету карты
        Console.ForegroundColor = this.Color;
        //получаем из атрибута в enum название карты
        string rank = Rank.GetDisplayName();
        //добавляем пробелы для выравнивания
        string output = $"[{UnicodeSign}{rank}]";
        if (output.Length < 9)
        {
            output = String.Concat(output, new string(' ', 9 - output.Length));
        }
        Console.Write(output);
    }
    /// <summary>
    /// Получение карты "заглушки", исп. для замещения выбывших карт в колоде
    /// </summary>
    /// <returns></returns>
    public static Card GetDummyCard()
    {
        var card = new Card(RankCard.Dummy, SuitCard.Dummy);
        card.Color = ConsoleColor.DarkGreen;
        return card;
    }
    /// <summary>
    /// Получение экземпляра такой же карты
    /// </summary>
    /// <param name="selectedCard">экземпляр карты</param>
    /// <returns></returns>
    public static Card GetTheSameCard(Card selectedCard)
    {
        return new Card(selectedCard.Rank, selectedCard.Suit);
    }
    public override string ToString()
    {
        string rank = Rank.GetDisplayName();
        var result = $"{Suit}-{rank}";
        return result;
    }
}

Далее класс Колоды

public class Deck
{
    private static Card[] _spades;
    private static Card[] _clubs;
    private static Card[] _hearts;
    private static Card[] _diamonds;
    protected static Random _random = new Random();
    public static int InitialNumberCards => Card.NumberRanks * Card.NumberSuits;
    //static ctor
    static Deck()
    {
        _spades = GetCardsArray(SuitCard.Spades);
        _clubs = GetCardsArray(SuitCard.Clubs);
        _hearts = GetCardsArray(SuitCard.Hearts);
        _diamonds = GetCardsArray(SuitCard.Diamonds);
    }
    private static Card[] GetCardsArray(SuitCard suitOfCard)
    {
        List<Card> listCards = new List<Card>();
        foreach (RankCard rank in Enum.GetValues(typeof(RankCard)))
        {
            if (rank == RankCard.Dummy) continue;
            listCards.Add(new Card(rank, suitOfCard));
        }
        return listCards.ToArray();
    }
    public enum OrderCards
    {
        Random, //случайный
        AscendingClubsDiamondsHeartsSpades, //по-возрастаню Трефы,Бубны,Червы,Пики
        DescendingClubsDiamondsHeartsSpades, //по-убыванию Трефы,Бубны,Червы,Пики
    }
    public List<Card> Cards { get; private set; } = new List<Card>();
    public int CurrentNumberCards => Cards.Count;
    //ctor
    public Deck() : this(OrderCards.Random)
    { }
    //ctor
    public Deck(OrderCards order)
    {
        switch (order)
        {
            case OrderCards.Random:
                SetRandomOrder();
                break;
            case OrderCards.AscendingClubsDiamondsHeartsSpades:
                SetAscendingOrder();
                break;
            case OrderCards.DescendingClubsDiamondsHeartsSpades:
                SetDescendingOrder();
                break;
            default:
                SetRandomOrder();
                break;
        }
    }
    private void SetRandomOrder()
    {
        //заполняем в порядке возрастания
        SetAscendingOrder();
        //формируем массив случайных чисел
        int[] randomIndexes = Enumerable.Range(0, InitialNumberCards)
                                        .OrderBy(n => _random.Next(0, Card.NumberRanks))
                                        .ToArray();
        //формируем новый список карт
        //путем выдергивания карт по случ.индексу
        List<Card> newList = new List<Card>();
        foreach (var index in randomIndexes)
        {
            newList.Add(Cards[index]);
        }
        //используем этот новый список
        Cards = newList;
    }
    private void SetAscendingOrder()
    {
        Cards.AddRange(_clubs);
        Cards.AddRange(_diamonds);
        Cards.AddRange(_hearts);
        Cards.AddRange(_spades);
    }
    private void SetDescendingOrder()
    {
        //не всё коту масленица, вы уж это сами как-нибудь реализуете...:)
        throw new NotImplementedException();
    }
    /// <summary>
    /// Вывод на консоль всей колоды
    /// </summary>
    public virtual void ShowDeck()
    {
        var cardsInRows = Cards.Count / 4;
        Console.WriteLine(new string('-', 115));
        for (int i = 0; i < Cards.Count; i += cardsInRows)
        {
            for (int j = 0; j < cardsInRows; j++)
            {
                Cards[i + j].ShowCard();
            }
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine();
        }
        Console.WriteLine(new string('-', 115));
    }
}

Далее класс Пасьянса

public class Solitaire : Deck
{
    public List<Card> HandThreeCard { get; private set; } = new List<Card>();
    //ctor
    public Solitaire() : base()
    { }
    //ctor
    public Solitaire(Deck.OrderCards orderCards) : base(orderCards)
    { }
    /// <summary>
    /// Взять из колоды 3 карты
    /// </summary>
    public void TakeThreeCards()
    {
        HandThreeCard.Clear();
        for (int i = 0; i < 3; i++)
        {
            //выбираем карты, которые не заглушки в колоде
            var notDummyCards = Cards.Where(c => c.Rank != RankCard.Dummy)
                                     .ToList();
            //если таких нет, то выходим из цикла
            if (notDummyCards.Count == 0) break;
            int index = _random.Next(0, notDummyCards.Count - 1);
            //определяем карту 
            var selectedCard = notDummyCards[index];
            //выбираем карту и добавляем ее в руку (точнее создаем такую же)
            HandThreeCard.Add(Card.GetTheSameCard(selectedCard));
            //теперь в самой колоде находим индекс такой же карты
            index = Cards.IndexOf(selectedCard);
            //замещаем карту в колоде заглукой
            Cards[index] = Card.GetDummyCard();
        }
    }
    /// <summary>
    /// Проверка руки на крайние карты одного цвета
    /// </summary>
    /// <returns>true если таких карт нет</returns>
    public bool CheckHandThreeCards()
    {
        return (HandThreeCard[0].Color == HandThreeCard[1].Color)
                    || (HandThreeCard[2].Color == HandThreeCard[1].Color);
    }
    /// <summary>
    /// Отображение колоды
    /// </summary>
    public override void ShowDeck()
    {
        base.ShowDeck();
    }
    /// <summary>
    /// Вывод на экран руки 3 карт
    /// </summary>
    public void ShowHandThreeCard()
    {
        Console.WriteLine(new string('-', 30));
        for (int i = 0; i < HandThreeCard.Count; i++)
        {
            HandThreeCard[i].ShowCard();
            Console.ForegroundColor = ConsoleColor.White;
        }
        Console.WriteLine();
        Console.WriteLine(new string('-', 30));
    }
}

А дальше используем наши классы и организуем алгоритм игры, как это от нас просят

static void Main(string[] args)
    {
        Console.WriteLine("==Solitaire==");
        Console.WriteLine();
        Console.WriteLine("Колода в порядке возрастания");
        Deck deck1 = new Deck(Deck.OrderCards.AscendingClubsDiamondsHeartsSpades);
        deck1.ShowDeck();
        Console.WriteLine();
        //--Начало игры
        Solitaire solitaire = new Solitaire();
        Console.WriteLine("Начало игры Солитер");
        solitaire.ShowDeck();
        Console.WriteLine();
        int i = 0;
        bool checkResult = false;
        while (i < 3)
        {
            Console.WriteLine($"Берем 3 карты в {++i}-й раз");
            solitaire.TakeThreeCards();
            Console.WriteLine("Рука");
            solitaire.ShowHandThreeCard();
            Console.WriteLine("Колода (вместо изъятых карт зеленые заглушки)");
            solitaire.ShowDeck();
            checkResult = solitaire.CheckHandThreeCards();
            if (checkResult)
                Console.WriteLine("Крайние карты одного цвета. Сбрасываем руку.");
            else
            {
                Console.WriteLine("Найдена верная рука!");
                Console.WriteLine("Игра закончилась успешно.");
                break;
            }
        }
        if (checkResult)
        {
            Console.WriteLine("Все попытки закончились.");
        }
        Console.ReadKey();
    }
}

Это всё. Можете свериться с тем, что удалось написать вам, может чем воспользуетесь.

READ ALSO
Как использовать две базы данных в проекте ASP.NET MVC?

Как использовать две базы данных в проекте ASP.NET MVC?

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

230
Считать из файла пароль PowerShell + C#

Считать из файла пароль PowerShell + C#

Есть такой скрипт PowerShell

279
Подключения к прокси

Подключения к прокси

Есть мой сервер на PHPЕсть прокси сервер http

266
Проблема с RB R::close()

Проблема с RB R::close()

Здравствуйте у меня возникла проблема с закрытием соединения Redbeans Тк у меня две БД то мне нужно два разных соединения но в некоторых местах...

238