7
\$\begingroup\$

I am learning c# and trying to wrap my head around OOP. This blackjack code is my first attempt. It works well enough, but it is probably terrible. Please let me know what to work on.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        bool playGame = true;
        int playerWins = 0;
        int dealerWins = 0;
        while (playGame)
        {
            bool hit = true;
            bool getResult = true;
            int getValues;
            Dealer dealer = new Dealer();
            Player player = new Player();

            while (hit)
            {
                player.AddCard();
                Console.Clear();
                if (player.CountValues(out getValues))
                    {
                        getResult = false;
                        ++dealerWins;
                        break;
                    }
                Console.WriteLine("Dealer shows one of his cards:");
                dealer.DisplayHand(0);
                Console.WriteLine("\nYour hand:");
                player.DisplayHand();
                Console.WriteLine("\nWhat will you do?");
                Console.WriteLine("(1) Hit");
                Console.WriteLine("(2) Stay");
                hit = userInput();
            }

            if (getResult)
            {
                player.CountValues(out getValues);
                Console.Clear();
                if (dealer.CountValues() >= getValues)
                {
                    Console.WriteLine("Dealer wins");
                    Console.WriteLine("Dealers hand:");
                    dealer.DisplayHand();
                    Console.WriteLine("\nDealer Points: {0}",dealer.CountValues());
                    Console.WriteLine("\nYour hand:");
                    player.DisplayHand();
                    Console.WriteLine("\nPlayer Points: {0}",getValues);
                    ++dealerWins;
                }
                else
                {
                    Console.WriteLine("Player wins");
                    Console.WriteLine("Dealers hand:");
                    dealer.DisplayHand();
                    Console.WriteLine("\nDealer Points: {0}",dealer.CountValues());
                    Console.WriteLine("\nYour hand:");
                    player.DisplayHand();
                    Console.WriteLine("\nPlayer Points: {0}",getValues);
                    ++playerWins;
                }
            }
            Console.WriteLine("\nDealer has won {0} times and you have won {1} times.",dealerWins,playerWins);
            Console.WriteLine("What will you do?");
            Console.WriteLine("(1) Play Again");
            Console.WriteLine("(2) Quit");
            playGame = userInput();
        }
    }

    public static bool userInput()
    {
        bool validInput = false;
        do
        {
            int number;
            string getValue = Console.ReadLine();
            bool result = Int32.TryParse(getValue, out number);
                if (result)
                {
                if (number == 1)
                {
                    validInput = true;
                    return true;    
                }
                else if (number == 2)
                {
                    validInput = true;
                    return false;
                }
                }
            Console.WriteLine("Choose a valid option.");
        }
        while (validInput == false);
        return false;
    }
}




public class Dealer
{
    List<Card> DealerHand = new List<Card>();
    private int _sumPoints;

    public Dealer()
    {
        DealerHand.Add(new Card());
        DealerHand.Add(new Card());
    }

    public void DisplayHand()
    {
        foreach (var card in DealerHand)
        {
                Console.WriteLine(card.Name);
        }
    }

    public void DisplayHand(int CardIndex)
    {
            Console.WriteLine(DealerHand[CardIndex].Name);
    }

    public int CountValues()
    {
        _sumPoints = 0;
        foreach (var card in DealerHand)
        {
                _sumPoints += card.Points;
        }
        return _sumPoints;
    }
}


public class Player
{
    List<Card> PlayerHand = new List<Card>();
    private int _sumPoints;

    public Player()
    {
        PlayerHand.Add(new Card());
    }

    public void DisplayHand()
    {
        foreach (var card in PlayerHand)
        {
                Console.WriteLine(card.Name);
        }
    }

    public void AddCard()
    {
        PlayerHand.Add(new Card());
    }

    public bool CountValues(out int getValues)
    {
        _sumPoints = 0;
        foreach (var card in PlayerHand)
        {
                _sumPoints += card.Points;
        }

        if (_sumPoints > 21)
        {
            foreach (var card in PlayerHand)
            {
                    if (card.Name == "Ace")
                {
                    _sumPoints -= 9;
                    getValues = _sumPoints;
                    return false;
                }
            }

            Console.WriteLine("Bust! Your hand value is over 21");
            Console.WriteLine("Your hand:");
            DisplayHand();
            Console.WriteLine("\nvalue: {0}",_sumPoints);
            getValues = _sumPoints;
            return true;
        }
        else
        {
            getValues = _sumPoints;
            return false;
        }
    }
}

public class Card
{
    private string _name;
    private int _points;

    public Card()
    {
    Random rnd = new Random();
    int randomCard = rnd.Next(1,14);

    switch (randomCard)
    {
        case 1:
            this._name = "Two";
            this._points = 2;
            break;
        case 2:
            this._name = "Three";
            this._points = 3;
            break;
        case 3:
            this._name = "Four";
            this._points = 4;
            break;
        case 4:
            this._name = "Five";
            this._points = 5;
            break;
        case 5:
            this._name = "Six";
            this._points = 6;
            break;
        case 6:
            this._name = "Seven";
            this._points = 7;
            break;
        case 7:
            this._name = "Eight";
            this._points = 8;
            break;
        case 8:
            this._name = "Nine";
            this._points = 9;
            break;
        case 9:
            this._name = "Ten";
            this._points = 10;
            break;
        case 10:
            this._name = "Jack";
            this._points = 10;
            break;
        case 11:
            this._name = "Queen";
            this._points = 10;
            break;
        case 12:
            this._name = "King";
            this._points = 10;
            break;
        case 13:
            this._name = "Ace";
            this._points = 10;
            break;
    }
    System.Threading.Thread.Sleep(100);
    }

    public string Name
    {
        get { return _name;  }
        set { _name = value; }
    }

    public int Points
    {
        get { return _points; }
        set { _points = value; }
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ (I don't know C# that well, so forgive me for stupid questions if applicable but) is there any reason you have a double indent in your case <n> lines? On the lines with this.something. \$\endgroup\$
    – user95591
    Commented Mar 20, 2017 at 19:44
  • \$\begingroup\$ @Riker no there isn't any reason for that. I have edited it to single indent. \$\endgroup\$ Commented Mar 20, 2017 at 19:52
  • \$\begingroup\$ @LearningToCSharp I think you could replace that switch/ case stuff using a dictionary. \$\endgroup\$ Commented Mar 20, 2017 at 19:58
  • 1
    \$\begingroup\$ @LearningToCSharp cool, thanks. I was just wondering. Also, in the future, it's best not to edit the code in your question. If people are writing a review at that moment, it can confuse them. \$\endgroup\$
    – user95591
    Commented Mar 20, 2017 at 19:59

3 Answers 3

7
\$\begingroup\$
this._name = "Ace";

Don't store information in strings. What happens if you want to check this value and type if (card.Name == "Ave")? Or what about if (card.Name == "ace")? Those checks will both fail. Create an enum with these values.

public enum Card
{
    Two,
    Three,
    // ...
    King,
    Ace
}

Now, if you have a card:

Card card = Card.Ace;

You can print the name like this:

Console.WriteLine(card.ToString()); // the .ToString() might be optional--don't remember offhand

Additionally, you can now simplify that massive switch statement somewhat:

var rnd = new Random();
var card = (Card)rnd.NextInt(0, 13);
var cardValue = GetValue(card);  // this method should switch over the enum value and return the appropriate value as shown below:

private int GetValue(Card card)
{
    switch (card)
    {
        case Card.Two:
            return 2;
        case Card.Three:
            return 3;
        // ...
        case Card.Ten:
        case Card.Jack:
        case Card.Queen:
        case Card.King:
        case Card.Ace:
            return 10;
    }
}

Don't put your logic in Main(). Main()'s job is to start and stop the program--not to do any logic. Your Main() should look something like this:

static void Main()
{
    PlayGame();
    Console.ReadKey(); // keep window from closing automatically
}

Look at all this duplication:

if (dealer.CountValues() >= getValues)
{
    Console.WriteLine("Dealer wins");
    Console.WriteLine("Dealers hand:");
    dealer.DisplayHand();
    Console.WriteLine("\nDealer Points: {0}",dealer.CountValues());
    Console.WriteLine("\nYour hand:");
    player.DisplayHand();
    Console.WriteLine("\nPlayer Points: {0}",getValues);
    ++dealerWins;
}
else
{
    Console.WriteLine("Player wins");
    Console.WriteLine("Dealers hand:");
    dealer.DisplayHand();
    Console.WriteLine("\nDealer Points: {0}",dealer.CountValues());
    Console.WriteLine("\nYour hand:");
    player.DisplayHand();
    Console.WriteLine("\nPlayer Points: {0}",getValues);
    ++playerWins;
}

The only two different lines are the first and the last. Those two lines, and only those two lines, should be separated. This is much shorter, and therefore easier to understand, debug, update, and maintain, and does the same thing:

if (dealer.CountValues() >= getValues)
{
    Console.WriteLine("Dealer wins");
    ++dealerWins;
}
else
{
    Console.WriteLine("Player wins");
    ++playerWins;
}

Console.WriteLine("Dealers hand:");
dealer.DisplayHand();
Console.WriteLine("\nDealer Points: {0}",dealer.CountValues());
Console.WriteLine("\nYour hand:");
player.DisplayHand();
Console.WriteLine("\nPlayer Points: {0}",getValues);
\$\endgroup\$
0
5
\$\begingroup\$
public static bool userInput()
{
    bool validInput = false;
    do
    {
        int number;
        string getValue = Console.ReadLine();
        bool result = Int32.TryParse(getValue, out number);
        if (result)
        {
            if (number == 1)
            {
                validInput = true;
                return true;    
            }
            else if (number == 2)
            {
                validInput = true;
                return false;
            }
        }
        Console.WriteLine("Choose a valid option.");
    }
    while (validInput == false);
    return false;
}

The loop condition validInput == false is pointless because the variable when tested will always be false, because in both places where you set it to true, you then return on the next line. So you might as well do this to accomplish the same logic:

public static bool UserInput()
{
    while (true)
    {
        string value = Console.ReadLine();

        if (value == "1")
            return true;
        else if (value == "2")
            return false;

        Console.WriteLine("Choose a valid option.");
    }
}

No need to parse the number, you're not going to use it, so just do a direct string comparison.

\$\endgroup\$
3
\$\begingroup\$

In blackjack, an Ace's value can be 1 or 11. You've got its value as 10. That's a bug. Being it's value is context sensitive to the rest of the hand, what you need is some sort of class that takes in a hand and returns a score.

Later, you can learn about interfaces & polymorphism and implement different scoring algorithms for different games.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.