C# Console Black Jack
Всем хай ,прогаю на c# 3 месяца ,сделал блек джек в консоли, можете оценить код и сказать какие у меня там ошибки, где можно сделать более красиво или эффективно.Помогите улучшить свой говнокод))
using System;
using System.Collections.Generic;
namespace _21
{
public class Deck
{
protected List<string> deck = new List<string>{"2", "2", "2", "2", "3", "3", "3", "4", "4", "4", "4", "4", "5", "5", "5", "5", "6", "6", "6", "6", "7", "7", "7", "7", "8", "8", "8", "8", "9", "9", "9", "9", "j", "j", "j", "j", "q", "q", "q", "q", "k", "k", "k", "k", "a", "a", "a", "a"};
protected string GiveCard()
{
Random rnd = new Random();
int cardindex = rnd.Next(0, deck.Count);
string card = deck[cardindex];
deck.RemoveAt(cardindex);
return card;
}
}
public class Player: Deck
{
private List<string> playershand = new List<string>();
private int playershandprice;
private int balance = 1000;
private int playersbet;
public void Bet(int bet)
{
balance -= bet;
playersbet = bet;
}
public int GetPlayersBet()
{
return playersbet;
}
public void GivePrize(int prize)
{
balance += prize;
}
public void Hand()
{
playershand.Add(GiveCard());
playershand.Add(GiveCard());
for (int i = 0; i < 2; i++)
{
int cardprice;
if(int.TryParse(playershand[i], out cardprice))
{
playershandprice += cardprice;
}
else
{
if(playershand[i]!="a")
{
playershandprice += 10;
}
else
{
if(playershandprice == 11)
{
playershandprice = 2;
}
else
{
playershandprice += 11;
}
}
}
}
}
public void ShowPlaersHandPrice()
{
Console.WriteLine(playershandprice);
}
public void AddCard()
{
playershand.Add(GiveCard());
int cardprice;
if (int.TryParse(playershand[playershand.Count-1], out cardprice))
{
playershandprice += cardprice;
}
else
{
if (playershand[playershand.Count - 1] != "a")
{
playershandprice += 10;
}
else
{
playershandprice += 11;
}
}
}
public int GetPlaersHandPrice()
{
return playershandprice;
}
public int GetPlayersBalance()
{
return balance;
}
}
public class Dealer: Deck
{
private string[] dealershand = {"",""};
private int dealershandprice;
private int dealersfirstcard;
public void Hand()
{
dealershand[0] = GiveCard();
dealershand[1] = GiveCard();
for (int i = 0; i < 2; i++)
{
int cardprice;
if (int.TryParse(dealershand[i], out cardprice))
{
dealershandprice += cardprice;
}
else
{
if (dealershand[i] != "a")
{
dealershandprice += 10;
}
else
{
if (dealershandprice == 11)
{
dealershandprice = 2;
}
else
{
dealershandprice += 11;
}
}
}
if (i == 0)
{
dealersfirstcard = cardprice;
}
}
}
public void ShowDealersFirstCard()
{
Console.WriteLine(dealersfirstcard);
}
public void ShowDealersHandPrice()
{
Console.WriteLine(dealershandprice);
}
public int GetDealersHandPrice()
{
return dealershandprice;
}
}
class Program
{
static void Main(string[] args)
{
string flag = "";
while(flag!="end")
{
Console.WriteLine("Добро пожаловать в блек джек");
Console.WriteLine("Введите start ,чтобы начать играть");
flag = Console.ReadLine();
if(flag == "start")
{
Deck deck = new Deck();
Player player= new Player();
Dealer dealer = new Dealer();
Console.Write("Ваш баланс:");
Console.WriteLine(player.GetPlayersBalance());
Console.Write("введите вашу ставку:");
player.Bet(int.Parse(Console.ReadLine()));
player.Hand();
Console.Write("Ваша рука:");
player.ShowPlaersHandPrice();
dealer.Hand();
Console.Write("1 карта дилера:");
dealer.ShowDealersFirstCard();
string flag1 = "";
while(flag1!="no")
{
Console.WriteLine("Введите yes , если xотите добрать карту, и no ,если не хотите");
flag1 = Console.ReadLine();
if(flag1 =="yes")
{
player.AddCard();
Console.Write("Ваша рука:");
player.ShowPlaersHandPrice();
}
}
if(player.GetPlaersHandPrice() > 21)
{
Console.WriteLine("Ваша рука:");
player.ShowPlaersHandPrice();
Console.Write("Рука дилера:");
dealer.ShowDealersHandPrice();
Console.WriteLine("Вы проиграли,ваша рука больше 21");
}
else if(player.GetPlaersHandPrice() < dealer.GetDealersHandPrice())
{
Console.WriteLine("Ваша рука:");
player.ShowPlaersHandPrice();
Console.Write("Рука дилера:");
dealer.ShowDealersHandPrice();
Console.WriteLine("Вы проиграли,рука дилера больше");
}
else if(player.GetPlaersHandPrice() > dealer.GetDealersHandPrice())
{
if(player.GetPlaersHandPrice()!=21)
player.GivePrize(player.GetPlayersBet()*2);
else
player.GivePrize(player.GetPlayersBet() * 3);
Console.WriteLine("Ваша рука:");
player.ShowPlaersHandPrice();
Console.Write("Рука дилера:");
dealer.ShowDealersHandPrice();
Console.WriteLine("Вы Выиграли");
Console.Write("Ваш баланс:");
Console.WriteLine(player.GetPlayersBalance());
}
else
{
player.GivePrize(player.GetPlayersBet());
Console.WriteLine("Ваша рука:");
player.ShowPlaersHandPrice();
Console.Write("Рука дилера:");
dealer.ShowDealersHandPrice();
Console.WriteLine("Ничья");
Console.Write("Ваш баланс:");
Console.WriteLine(player.GetPlayersBalance());
}
}
else
{
flag = "end";
}
}
}
}
}
Ответы (1 шт):
- Много
if-else. - Дублируете код.
string flagплохо, используйте специально созданный для этогоenum.- Ошибка в игре, где у игрока и дилера своя колода карт.
- Есть проблемы с именованием, а именно
dealershandprice, принято писатьdealersHandPrice, каждое слово с большой буквы. if (dealershand[i] != "a")- наверно стоит сделать отдельный класс, который будет содержать в себе информацию о карте?- Наследуете
PlayerотDeck, это если бы вы наследовали машину от карандаша. Игрок не может быть колодой карт. player.Bet(int.Parse(Console.ReadLine()));- а если напишуwqeqe?- Можно брать бесконечное число карт, даже если у игрока уже выше 21.
- После игры нужно повторно писать
start, зачем тогда баланс, если он сбивается?
Это, пожалуй, минимум, который я нашел, мельком проверив ваш код. Давайте теперь попробуем сделать более-менее приемлемо.
Создадим новый класс, назовем его
Card, пусть отвечает за одну конкретную карту (тут играйтесь как хотите, я для примера добавлю название):public class Card { public Card(string name, int value, CardType type) => (Name, Value, Type) = (name, value, type); public string Name { get; init; } public int Value { get; init; } public CardType Type { get; init; } }Тип тут является простым
enum:public enum CardType { Number, Jack, Queen, King, Ace }Создадим теперь колоду карт (класс
Deck):public class Deck { private readonly List<Card> cards = new(); public Deck() => GenerateCards(); public Card Take() { if (IsEmpty) return null; var card = cards[new Random().Next(cards.Count)]; cards.Remove(card); return card; } public bool IsEmpty => !cards.Any(); public int Count => cards.Count; private void GenerateCards() { foreach (var type in Enum.GetValues<CardType>()) { if (type is CardType.Number) { for (int i = 2; i <= 9; i++) { cards.AddRange(CreateCardsByType(type, i)); } } else { cards.AddRange(CreateCardsByType(type)); } } } private IEnumerable<Card> CreateCardsByType(CardType type, int value = 0) { List<Card> result = new(); for (int i = 0; i < 4; i++) { Card card = type switch { CardType.Number => new($"{value}", value, type), CardType.Jack => new($"Валет", 10, type), CardType.Queen => new($"Дама", 10, type), CardType.King => new($"Король", 10, type), CardType.Ace => new($"Туз", 11, type), }; result.Add(card); } return result; } }Здесь я заменил ваш статичный набор на простую генерацию.
List<Card> cards- набор наших карт.public Deck() => GenerateCards();- вызываем генерацию при инициализации класса.Card Take()- Взять (если есть) карту и удалить ее из колоды.bool IsEmpty- Проверяем, есть ли еще карта..Any()- это LINQ, можно заменить на нечто простое, по типуcards.Count == 0(cards is { Count: 0 }).int Count- коллекция карт наружу не отдается, а число карт может и понадобиться.void GenerateCards()- Генерируем колоду карт.IEnumerable<Card> CreateCardsByType(...)- Создаем 4 карты одного типа.
Создаем игрока (класс
Player):public class Player { private Deck deck; private List<Card> cards = new(); public Player(string name, Deck deck) => (Name, this.deck) = (name, deck); public string Name { get; init; } public int Money { get; private set; } = 1000; public int Score { get; private set; } public int Cards => cards.Count; public bool IsLost => Score > 21; public bool Take() { if (IsLost) return false; var card = deck.Take(); cards.Add(card); Score += card.Value; return !IsLost; } public void Reset() { Score = 0; cards.Clear(); } }Я не стал тут реализовывать функционал денег, думаю справитесь сами, задача была просто и наглядно показать, как стоит поступить, а конкретно то, что в классе есть только необходимый для игрока функционал.
Так, колода карт есть, игрок есть, дилер, по сути, тоже есть (ведь это тоже в некотором роде игрок, верно?), осталось наклепать класс игры (
Game):public class Game { private Deck deck = new(); private Player[] players; public Game() { players = new[] { new Player("Дилер", deck), new Player("Игрок", deck) }; Start(); } public bool IsEnded { get; private set; } public void Start() { bool replay = true; while (replay) { Console.Clear(); Turn(); IsEnded = players.Any(x => x.IsLost); Console.ReadLine(); if (IsEnded) replay = Replay(); } } private void Turn() { foreach (var player in players) { var status = player.Take() ? "Еще в игре" : "Проиграл"; Console.WriteLine($"У {player.Name} {player.Score}, он {status}"); } } private bool Replay() { bool result = false; while (true) { Console.Clear(); Console.Write("Повторить? (y/n): "); var value = Console.ReadLine(); if (value is "y" or "n") { result = value is "y"; break; } } if (result) { Reset(); } return result; } private void Reset() { deck = new(); foreach (var player in players) { player.Reset(); } } }Опять же, я многое не сделал, лишь показал каркас того, как стоило бы поступить. Этот класс будет поочередно брать карту у каждого игрока из массива, а когда один из них зайдет за пределы, игра завершится и предложит нам переиграть.
Этим ответом я не пытаюсь решить ваши косяки (о которых написал выше), моя задача показать вам как в языке C# используются базовые принципы ООП, а именно, создаются отдельные объекты, со своей логикой и значениями, как они друг с другом взаимодействуют. Старайтесь следовать этим правилам, а также правилам SOLID, это очень сильно облегчит вам жизнь!
Из того, что нужно доделать (домашнее задание?):
- Реализовать валюту игрока (ее трату и пополнение, а также запоминание, чтобы каждая игра начиналась со старым балансом.).
- Реализовать логику туза, ведь эта карта может дать как 1, так и 11.
- Реализовать запрос "взять еще карту?".
- Реализовать завершение игры, если закончились карты.
- Постараться вынести все взаимодействие с консолью в отдельный класс.
В общем, удачи вам в изучении C#!