Playing Card Class in C# - c#

Hello I'm a first year student and for one of our assignements about C# we are asked to make a blackjack game which includes a Playing Card Class with a property "cardValue" which has an int value from 1 to 13 and a property "description" which has the name of the card "1, 2, ..., Jack, Queen, King". I'm trying to use the "cardValue" property to determine the "description".
This is the code I have written so far:
class Card
{
public int Cardvalue{ get; private set; } = new Random().Next(1, 14);
private string description;
public string Description
{
get { return description; }
set
{
switch (Cardvalue)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
description= Cardvalue.ToString();
break;
case 11:
description= "Jack";
break;
case 12:
description= "Queen";
break;
case 13:
description= "King";
break;
}
}
}
}
I already figured out it doesn't work because I can't use "cardValue" to determine "description". But I'm struggling with finding a solution which does work. I know it may possibly be a very basic question but I would really appreciate some help!

You are missing something important the suit !
This is a potential solution:
public enum Suit
{
Clubs,
Diamonds,
Spades,
Hearts
}
public class Card
{
public string DisplayName { get; set; }
public Suit Suit { get; set; }
public int Value { get; set; }
}
Leverage of the built-in Queue<> object in C#. That collection has almost all the functionality we need to implement a deck of cards.
public static class DeckCreator
{
public static Queue<Card> CreateCards()
{
Queue<Card> cards = new Queue<Card>();
for(int i = 2; i <= 14; i++)
{
foreach(Suit suit in Enum.GetValues(typeof(Suit)))
{
cards.Enqueue(new Card()
{
Suit = suit,
Value = i,
DisplayName = GetShortName(i, suit)
});
}
}
return Shuffle(cards);
}
}
Finally, we need to handle the GetShortName() method. We don't want to be displaying "Ace of Spades" every time that card appears, rather we want to show the short name "AS" (or "5C" for 5 of Clubs, or "KD" for King of Diamonds, and so on). So we need a method to assign this short name (change it to our needs ie: replace J with Jack) to each card, like so:
public static class DeckCreator
{
public static Queue<Card> CreateCards() { ... }
private static string GetShortName(int value, Suit suit)
{
string valueDisplay = "";
if (value >= 2 && value <= 10)
{
valueDisplay = value.ToString();
}
else if (value == 11)
{
valueDisplay = "J";
}
else if (value == 12)
{
valueDisplay = "Q";
}
else if (value == 13)
{
valueDisplay = "K";
}
else if (value == 14)
{
valueDisplay = "A";
}
return valueDisplay + Enum.GetName(typeof(Suit), suit)[0];
}
}

I solved it this way, using the way #madreflection described and #Flydog57 clarified:
class Card
{
public int Cardvalue{ get; private set; } = new Random().Next(1, 14);
public string Description
{
get
{
switch (Cardvalue)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
return Cardvalue.ToString();
case 11:
return "Jack";
case 12:
return "Queen";
case 13:
return "King";
default:
return "";
}
}
}
}
P.S. I first also tried using a constructor like #Taekahn suggested but I couldn't figure out how I would have to do that as it didn't seem to want to work either. So any help is still welcomed.
I also know that jack, queen and king is worth 10 in blackjack but the assignement told us to use the values of 11, 12 and 13.

Related

Program is not producing expected result based on case statement

I have a console app that waits for the User to enter a number between 1 and 4. Depending on the selection, a case statement will then print out the appropriate console statement, or go to a different method. When I start the program and enter the number, nothing is returned and the program ends.
if the user selects number 1 I want to print out a line of text and then execute program called NewEntry. It doesn't seem to even start that program.
class Program
{
static void Main(string[] args)
{
//initial Prompt
Console.WriteLine("***Welcome to the Asset Directory***");
Console.WriteLine("Please Select an Option");
Console.WriteLine("1. New Entry");
Console.WriteLine("2. Edit Entry");
Console.WriteLine("3. Look Up");
Console.WriteLine("4. Print Master List");
int userInput;
userInput = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(userInput);
switch (userInput)
{
case '1':
Console.WriteLine("1. New Entry");
NewEntry();
break;
case '2':
Console.WriteLine("2. Edit Entry");
break;
case '3':
Console.WriteLine("Look Up");
break;
case '4':
Console.WriteLine("4. Print Master List");
break;
default:
Console.WriteLine("Invalid Selection");
break;
}
}
static void NewEntry ()
{
Console.WriteLine("Enter the DSCADA Asset Information");
Test_RTU = new DSCADA_RTU();
Test_RTU.StationName = Console.ReadLine();
Test_RTU.RTUmake = Console.ReadLine();
Test_RTU.RTUtype = Console.ReadLine();
Test_RTU.CommunicationType = Console.ReadLine();
Test_RTU.DateInService = Console.ReadLine();
}
}
class Test_RTU
{
public string EDiv { get; set; } //division that owns the asset
public string StationName { get; set; } // name of station RTU is located
public string RTUmake {get; set;}
public string RTUtype { get; set; }
public string CommunicationType { get; set; }
public string DateInService { get; set; }
}
Your switch cases should look like this:
case 1:
...
case 2:
...
case 3:
...
case 4:
...
not this:
case '1':
...
case '2':
...
case '3':
...
case '4':
...
userInput is an int, so the cases should be int literals as well. The literals that you are using (such as '1') are char literals. There just so happens to be an implicit conversion from char to int, converting '1' to the integer 49, '2' to the integer 50, etc. Because of this implicit conversion, your code passes compilation, but doesn't work as expected.

C# switch case forcing

Hi there I am making a C# windows forms app, I made a switch with all my teammates birthdays in order to calculate their birthday age, however I want to add the functionality that if today is their birthday a message appears.
Therefore I need something that goes into EACH CASE of the switch and there I will add a validation like if today's date is equal to bday, then messageshow "its name 1 birthday, today!"
switch (name)
{
case "name 1":
bday = DateTime.Parse("11.11.1988");
break;
case "name 2":
bday = DateTime.Parse("11.12.1988");
break;
case "name 3":
bday = DateTime.Parse("03.12.1987");
break;
}
Why dont you use a Dictionary.
Dictionaries use other objects as Keys to retrieve their values.
In your case you could map all the birthdays to their names like:
Dictionary<string, DateTime> birthdays = new Dictionary<string, DateTime>;
//Add values like this
birthdays.Add("name 1", DateTime.Parse("11.11.1988"));
birthdays.Add("name 2", DateTime.Parse("11.12.1988"));
...
//Then you could loop through all the entries
foreach(KeyValuePair<string, DateTime> entry in birthdays)
{
if(entry.Value.Day == DateTime.Now.Day && entry.Value.Month == DateTime.Now.Month)
{
Console.WriteLine(entry.Key + " has birthday!");
}
}
Based on what you provided in your snippet, you could do this sort of check outside of the case statement. Example:
public void WhateverYourMethodIs()
{
switch (name)
{
case "name 1":
bday = DateTime.Parse("11.11.1988");
break;
case "name 2":
bday = DateTime.Parse("11.12.1988");
break;
case "name 3":
bday = DateTime.Parse("03.12.1987");
break;
}
if (this.IsBirthday(bday))
{
// do whatever you want for when it's the name's birthday.
}
}
public bool IsBirthday(DateTime bday)
{
if (bday.Day == DateTime.Now.Day && bday.Month == DateTime.Now.Month)
return true;
return false;
}
note the above would not take into account leap day birthdays.
Based on your comments, it sounds like you're hoping to evaluate the birthdays of all names regardless of the switch. This won't work in your current approach. bday is a single value that can only be attributed to the current "name".
One way to accomplish what you're hoping for would be to use a class to represent a name as so:
public class User
{
public string Name { get; set; }
public DateTime Birthday { get; set; }
public bool IsBirthday
{
get
{
if (Birthday.Day == DateTime.Now.Day && Birthday.Month == DateTime.Now.Month)
return true;
return false;
}
}
}
public class SomeClass
{
private List<User> Users = new List<User>();
public void PopulateNames()
{
Users.Add(new User()
{
Name = "name 1",
Birthday = DateTime.Parse("11.11.1988")
};
Users.Add(new User()
{
Name = "name 2",
Birthday = DateTime.Parse("11.12.1988")
};
// etc
}
public void DoSomethingOnUsersWithABirthday()
{
foreach (User user in Users)
{
if (user.IsBirthday)
{
// do something for their birthday.
Console.WriteLine(string.format("It's {0}'s birthday!", user.Name));
}
}
}
}

How to Limit a Parameter in a Method?

I have a method that I would like to pass an option to, but as a switch. It is hard for me to explain so I will include the class:
class Special
{
int Var1;
int Var2;
public void Add1(int option, int variable)
{
int ToReturn;
ToReturn = variable + 1;
switch(option)
{
case 1:
Var1 = ToReturn;
break;
case 2:
Var2 = ToReturn;
break;
}
}
}
Is there a way I can limit the value of option to 1 or 2? Can I add any information to the Add1 so that when it is called it informs the programmer as to which values it may be, and what each option does?
I have given an example class, but my class contains many more variables this may apply to.
Yes:
public enum Option
{
Option1,
Option2
}
public void Add1(Option option, int variable)
{
int ToReturn;
ToReturn = variable + 1;
switch(option)
{
case Option1:
Var1 = ToReturn;
break;
case Option2:
Var2 = ToReturn;
break;
}
}
Looks like you want to use enumerations, basically placeholders for statically defined values.
I could think of a number of ways to do what you are asking however if I was in your scenario (providing I have understood your question correctly) I would be using an enum...
enum Options {
Option1 = 1,
Option2 = 2
}
class Special
{
int Var1;
int Var2;
public void Add1(Options option, int variable)
{
int ToReturn;
ToReturn = variable + 1;
switch(option)
{
case Options.Option1:
Var1 = ToReturn;
break;
case Options.Option2:
Var2 = ToReturn;
break;
}
}
}

C# get/set solution

To give some background I'm trying to solve the Project Euler Problem 54 involving poker hands. Though there's infinite approaches to this. What I would like to do is enumerate through a list of strings, for example:
{ "8C", "TS", "KC", "9H", "4S" };
I would like to "get" an instance of class card with properties value, and suit, for each respective string. I've not yet utilized get/set so maybe there is an obvious approach to this I'm missing.
Ultimately I would like to have a list of objects type Card, I don't mind building all the card's ahead of time, such that "2H" returns an instance of type Card where suit = Hearts, and value = 2, for example.
I know this code is wrong, but it should give an idea of what I'm trying to do. Any suggestions would be appreciated.
class Card
{
public string suit;
public int value;
public string cardname
{
get
{
if (cardname == "2H") Card TwoH = new Card();
TwoH.suit = "Hearts"
TwoH.value = 2;
return TwoH;
}
}
}
Why not make a constructor that fills suit and value based on a string parameter
public Card(string name)
{
switch(name)
{
case "2H":
this.suit = "Hearts";
this.value = 2;
break;
//...
}
}
This might not be the exact solution you seem to be asking for but if the values you'll be getting (eg 2H, 3C etc) are all 2 characters long, then you can try this:
public class Card
{
public string suit { get; set; }
public int value { get; set; }
public static Card GetCard(string cardName)
{
string tmpSuit;
int tmpValue;
char[] cardNameParts = cardName.ToCharArray();
switch(charNameParts[0])
{
case "A":
tmpValue = 1;
break;
case "2":
tmpValue = 2;
break;
...
}
switch(charNameParts[1])
{
case "H":
tmpSuit= "Hearts";
break;
case "C":
tmpSuit= "Clubs";
break;
...
}
return new Card() { suit = tmpSuit, value = tmpValue };
}
}
I would do it like that:
public class Card
{
public string Suit { get; set; }
public int Value { get; set; }
public static Card FromString(string s)
{
if (s == "2H") return new Card() { Suit = "Hearts", Value = 2 };
else if (s == "....")
...
else return null;
}
}
I have converted your suit and value field into properties and instead of some getter method which in your case wouldn't work I have added a static method.
You can use it like this Card card2H = Card.FromString("2H");
Maybe use two switch statements, first
switch (cardname[0])
{
...
}
then
switch (cardname[1])
{
...
}
Before that, check that cardname.Length == 2. In each switch, have a default section where you throw an exception in case the char value doesn't make sense.

Best way to represent game card class in C#

I use class Card which contains 2 enumerated properties (suite - hearts diamonds spades and clubs) and card value from 2 to A. And overrides ToString() method to returns something like Ah Ad etc. All ok, but enum value can't starts with number, therefore my card value enumerated looks like x2, x3, x4 ... it is not beautiful.
Also need simple approach to parse few cards from single string.
Who know the best approach to design this class?
Couldn't you assign Jack, Queen, King, and Ace to be 11, 12, 13, and 14, respectively? It'd end up looking something like:
public class Card
{
public int Value { get; private set; }
public enum SuitType
{
Clubs, Spades, Hearts, Diamonds
}
public SuitType Suit { get; private set; }
public Card(int value, SuitType suit)
{
Suit = suit;
Value = value;
}
public Card(string input)
{
if (input == null || input.Length < 2 || input.Length > 2)
throw new ArgumentException();
switch (input[0])
{
case 'C': case 'c':
Suit = SuitType.Clubs;
break;
case 'S': case 's':
Suit = SuitType.Spades;
break;
case 'H': case 'h':
Suit = SuitType.Hearts;
break;
case 'D': case 'd':
Suit = SuitType.Diamonds;
break;
default:
throw new ArgumentException();
}
int uncheckedValue = (int)input[1];
if (uncheckedValue > 14 || uncheckedValue < 1)
throw new ArgumentException();
Value = uncheckedValue;
}
public string encode()
{
string encodedCard = "";
switch (Suit)
{
case SuitType.Clubs:
encodedCard += 'c';
break;
case SuitType.Spades:
encodedCard += 's';
break;
case SuitType.Hearts:
encodedCard += 'h';
break;
case SuitType.Diamonds:
encodedCard += 'd';
break;
}
encodedCard += (char) Value;
return encodedCard;
}
public override string ToString()
{
string output = "";
if (Value > 10)
{
switch (Value)
{
case 11:
output += "Jack";
break;
case 12:
output += "Queen";
break;
case 13:
output += "King";
break;
case 14:
output += "Ace";
break;
}
}
else
{
output += Value;
}
output += " of " + System.Enum.GetName(typeof(SuitType), Suit);
return output;
}
}
Edit:
I added some string functionality.
I took structure of Card(string input) from Jon Hanna's answer.
There's an obvious numeric value for the pip-cards, and we can add J=11, Q=12, K=13.
It may be more convenient to have A=14 than A=1 depending on the game being modelled (so one can more simply compute different relative values of hands).
Enums gives no real advantage, especially since enums allow out-of-range values unless you explicitly check for them (e.g. there is nothing to stop someone assigning (CardValue)54 to the card-value enumeration value).
ToString can be aided with an array of the values {null,"1","2","3","4","5","6","7","8","9","10","J","Q","K"}. Likewise {'♥','♦','♠','♣'} could give a nicer output.
Parsing always trickier than outputting a string, even if you are very strict in what you accept, as you have to deal with the potential for invalid input. A simple approach would be:
private Card(string input)
{
if(input == null)
throw new ArgumentNullException();
if(input.length < 2 || input.length > 3)
throw new ArgumentException();
switch(input[input.Length - 1])
{
case 'H': case 'h': case '♥':
_suit = Suit.Hearts;
break;
case 'D': case 'd': case '♦':
_suit = Suit.Diamonds;
break;
case 'S': case 's': case '♠':
_suit = Suit.Spades;
break;
case 'C': case 'c': case '♣':
_suit = Suit.Clubs;
break;
default:
throw new ArgumentException();
}
switch(input[0])
{
case "J": case "j":
_cardValue = 11;
break;
case "Q": case "q":
_cardValue = 12;
break;
case "K": case "k":
_cardValue = 13;
break;
case "A": case "a":
_cardValue = 1;
break;
default:
if(!int.TryParse(input.substring(0, input.Length - 1), out _cardValue) || _cardValue < 2 || _cardVaue > 10)
throw new ArgumentException;
break;
}
}
public static Card Parse(string cardString)
{
return new Card(cardString);
}
You might want to add a static method that read a larger string, yield returning cards as it parsed, to allow for easier encoding of several cards.
When I first started on the card.dll, I was using enumerations for suits and card rankings but then I didn't want to have to deal with that same issue and writing extra code to compensate for the strings, there for I wrote a abstract class Info with only two variables
(Flag (byte)) and (Name(string)) to be implemented by the Rank class and Suit class which would be members of the Card class. I have found this to work a lot better for naming conventions and filtering purposes. I love using enums but having to work around variable naming can be a hassle so sometimes it is best not to if you have to get the variable name as string.
So when the Card constructor get called the card ID is entered and then it passes into the Rank and Suit which will then separate what the ID means in code (101 = 100 (suit flag) +
1 (rank flag)). The protected abstract SetName(int cardID) and SetFlag(int cardID) while handle the rest from there in the info's constructor via Rank and Suit. No more issues with the enumeration and it can still be filtered by number via the Flag.
This card naming system uses a 1 through 4 * 100 (telling the suit flag) + 1 through 13 (for card rank). 500 + 14 through 16 are Little Joker, Big Joker, and Wild.
public class Card
{
short id;
public Card(string zFile)
{
this.id = Convert.ToInt16(zFile.Split('.')[0].Trim());
this.Rank = new Rank(id);
this.Suit = new Suit(id);
}
public override string ToString()
{
if (Suit.Flag == 5)
return Suit.Name;
return string.Concat(Rank.Name, " of ", Suit.Name);
}
public override int GetHashCode()
{
return id;
}
public Rank Rank { get; private set; }
public Suit Suit { get; private set; }
public static Card GetGreaterRank(Card value1, Card value2)
{
return (value1.Rank >= value2.Rank) ? value1 : value2;
}
public static bool CompareRank(Card value1, Card value2)
{
return (value1.Rank.Flag == value2.Rank.Flag);
}
public static bool CompareSuit(Card value1, Card value2)
{
return (value1.Suit.Flag == value2.Suit.Flag);
}
};
public abstract class Info
{
protected Info(short cardID)
{
Flag = SetFlag(cardID);
}
protected string SetName(short cardID, params string[] names)
{
for (int i = 0; i < names.Length; i++)
{
if (Flag == (i + 1))
return names[i];
}
return "Unknown";
}
protected abstract byte SetFlag(short cardID);
public static implicit operator byte(Info info)
{
return info.Flag;
}
public byte Flag { get; protected set; }
public string Name { get; protected set; }
};
public class Rank : Info
{
internal Rank(short cardID) : base(cardID)
{
string name = SetName(cardID, "A","2","3","4","5","6","7",
"8","9","10","J","Q","K","Little Joker","Big Joker","Wild");
Name = (name == "Unknown") ? string.Concat(name, " Rank") : name;
}
protected override byte SetFlag(short cardID)
{
return Convert.ToByte(cardID.ToString().Remove(0, 1));
}
};
public class Suit : Info
{
internal Suit(short cardID) : base(cardID)
{
string name = SetName(cardID,"Clubs","Diamonds","Hearts","Spades");
Name = (name == "Unknown") ? string.Concat(name, " Suit") ? name;
}
protected override byte SetFlag(short cardID)
{
return Convert.ToByte(cardID.ToString().Remove(1));
}
};
So now if you have your card image file named 101.png and pass it into the Card ctor it will pass to the Rank and Suit getting the info for you. Really all you are doing in giving the image file a code(numeric) for a name.
I would probably start out with 2 enums, 1 representing the Suits and 1 representing the Faces. Then declare a public property "Suit" and a public property "Face" based off of these enums. You will also probably need an array with the different unique values that a card can have (i.e. 1 throught 13).
You can start enums with number (although it is preferred to start at zero)
public enum Card
{
Two = 2,
Three,
Four,
...
}
Scratch what I wrote before, this is better.
using System;
enum Suit
{
Clubs,
Hearts,
Diamonds,
Spades
}
class Card
{
Suit Suit
{
get;
private set;
}
int Value
{
get;
private set;
}
Card(Suit suit, int value)
{
Suit = suit;
Value = value;
}
private const string[] valsToString = new string[] { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" };
bool IsValid()
{
return Value >= 2 && Value <= 14;
}
override string ToString()
{
return string.Format("{0} of {1}", valsToString[Value - 2], Suit);
}
}

Categories

Resources