Program is not producing expected result based on case statement - c#

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.

Related

Playing Card Class in 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.

Unable to access object properties from the same class but different method in C#

I am unable to access the properties of the object student1 that has been created in the Main() method of the Program class in the method ClassOperations() of the same class. I keep getting
error CS0103: The name 'student1' does not exist in the current
context
using System;
namespace Trials
{
public class Students
{
public int maths;
public int science;
public int english;
public int secondLang;
public int socialScience;
public string name;
public Students(int[] inputMarks)
{
maths = inputMarks[0];
science = inputMarks[1];
english = inputMarks[2];
secondLang = inputMarks[3];
socialScience = inputMarks[4];
}
}
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter your name: ");
string inputName = Console.ReadLine();
int[] marks = new int[5];
Console.WriteLine("Enter the maths marks: ");
marks[0] = int.Parse(Console.ReadLine());
Console.WriteLine("Enter the Science marks: ");
marks[1] = int.Parse(Console.ReadLine());
Console.WriteLine("Enter the English marks: ");
marks[2] = int.Parse(Console.ReadLine());
Console.WriteLine("Enter the Second language marks: ");
marks[3] = int.Parse(Console.ReadLine());
Console.WriteLine("Enter the Social Science marks: ");
marks[4] = int.Parse(Console.ReadLine());
Students student1 = new Students(marks);
student1.name = inputName;
ClassOperations();
}
static void ClassOperations()
{
Console.WriteLine("Enter input :");
int input = int.Parse(Console.ReadLine());
switch (input)
{
case 1:
Console.WriteLine(student1.name);
break;
case 2:
Console.WriteLine(student1.maths);
break;
case 3:
Console.WriteLine(student1.science);
break;
case 4:
Console.WriteLine(student1.english);
break;
case 5:
Console.WriteLine(student1.secondLang);
break;
case 6:
Console.WriteLine(student1.socialScience);
break;
}
}
}
}
The error is telling you the problem: local variables (student1) declared in a method (Main) are not accessible within other methods (ClassOperations, the current context). You have several options:
(static) property
(static) field
method parameter
In this example, the "best" option is to pass your student1 variable as a parameter to the ClassOperations method:
static void Main(string[] args) {
// setup elided
Students student1 = new Students(marks);
student1.name = inputName;
// pass as parameter
ClassOperations(student1);
}
static void ClassOperations(Students student) {
// access value via new name "student"
Console.WriteLine(student.name);
}
Based on your comments, here is what the alternative with a field could look like:
static Students student; //static field
static void Main(string[] args) {
// setup elided
// initialize static field
student = new Students(marks);
student.name = inputName;
ClassOperations();
}
static void ClassOperations() {
// access value via static field "student"
Console.WriteLine(student.name);
}

I want to search, delete and update from a text file in C#

Like the title, I want to search, delete and update from a text file. I've a menu, an add functions and a view all functions but I couldn't figure out how to do search, delete and update from a text file.
edit:
text file example:
stdID|stdName|stdPhone|stdAge|stdGrading
00001|John|17158721|17|B
00002|Alex|31992592|17|A
So for the search function. I want to have the user input the ID and they get the entire string of information from the text file.
For delete function. I want the user to input the ID and the entire string of information with the exact ID will be delete from the text file.
For Update, I want the user to input the ID and they can re-enter the information of the string into the text file.
Here is the menu, add and view functions.
class Program
{
static void Main(string[] args)
{
bool showMenu = true;
while (showMenu)
{
showMenu = MainMenu();
}
}
private static bool HandleError(string message)
{
Console.Clear();
Console.WriteLine(message);
Console.ReadLine();
return true;
}
private static bool MainMenu()
{
Console.Clear();
Console.WriteLine("=======================");
Console.WriteLine(" Choose an option:");
Console.WriteLine(" 1. Manage Students");
Console.WriteLine(" 2. Manage Lecturers");
Console.WriteLine(" 3. Exit");
Console.WriteLine("=======================");
Console.Write("\r\nPlease choose: ");
try
{
switch (Console.ReadLine())
{
case "1":
ManageStudents();
return true;
case "2":
ManageLecturers();
return true;
case "3":
return false;
default:
return HandleError("!! Invalid input !!");
}
}
catch (Exception e)
{
return HandleError("!! Execution error !!");
}
}
private static bool ManageStudents()
{
Console.Clear();
Console.WriteLine("========================");
Console.WriteLine(" Choose an option:");
Console.WriteLine(" 1. Add a new student");
Console.WriteLine(" 2. View all students");
Console.WriteLine(" 3. Search students");
Console.WriteLine(" 4. Delete students");
Console.WriteLine(" 5. Update students");
Console.WriteLine(" 6. Back to main menu");
Console.WriteLine("========================");
Console.Write("\r\nPlease choose: ");
Program program = new Program();
try
{
switch (Console.ReadLine())
{
case "1":
program.AddStudents();
return true;
case "2":
ViewStudents();
return true;
case "3":
SearchStudents();
return true;
case "4":
DeleteStudents();
return true;
case "5":
UpdateStudents();
return true;
case "6":
return false;
default:
return HandleError("!! Invalid input !!");
}
}
catch (Exception e)
{
return HandleError("!! Execution error !!");
}
}
struct Student
{
public int stdID;
public string stdName;
public int stdPhone;
public int stdAge;
public string stdGrading;
}
private Student tStudent;
static FileStream F;
StreamWriter W;
StreamReader R;
private void AddStudents()
{
Console.Clear();
Console.Write("Enter student ID: ");
tStudent.stdID = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter student full name: ");
tStudent.stdName = Console.ReadLine();
Console.Write("Enter student phone number: ");
tStudent.stdPhone = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter student age: ");
tStudent.stdAge = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter student grading: ");
tStudent.stdGrading = Console.ReadLine();
F = new FileStream(#"C:\Text\students.txt", FileMode.Append, FileAccess.Write);
W = new StreamWriter(F);
W.Write(tStudent.stdID);
W.Write("|");
W.Write(tStudent.stdName);
W.Write("|");
W.Write(tStudent.stdPhone);
W.Write("|");
W.Write(tStudent.stdAge);
W.Write("|");
W.Write(tStudent.stdGrading);
W.Write("|");
W.Flush();
W.Close();
}
private static void ViewStudents()
{
Console.Clear();
var lines = File.ReadAllLines(#"C:\Text\students.txt")
.Select(x => x.Split('|'))
.ToArray();
var widths = Enumerable.Range(0, lines[0].Length)
.Select(x => lines.Max(y => y[x].Length))
.ToArray();
foreach (var line in lines)
Console.WriteLine(string.Join(" | ", line.Select((x, i) => x.PadRight(widths[i], ' '))));
Console.ReadLine();
}
Here is the search and delete code I found somewhere on the internet I tried to put it in mine but I am sure that I butchered it.
private static void SearchStudents()
{
Console.Clear();
StreamReader sr = new StreamReader(#"C:\Text\students.txt");
string line;
while ((line = sr.ReadLine()) != null)
{
Console.Write("Enter student ID here: ");
if (line == Console.ReadLine())
{
dem += 1;
}
}
Console.WriteLine("Search result: ");
Console.ReadLine();
}
private static void DeleteStudents()
{
string tempFile = Path.GetTempFileName();
using (StreamReader sr = new StreamReader(#"C:\Text\students.txt"))
{
using (StreamWriter sw = new StreamWriter(tempFile))
{
string line;
while ((line = sr.ReadLine()) != null)
{
if (line != Console.ReadLine())
sw.WriteLine(line);
}
}
}
File.Delete("demo.txt");
File.Move(tempFile, "demo.txt");
Console.WriteLine("da xoa xong");
Console.ReadKey();
}
private static void UpdateStudents()
{
}
Sorry for my butchered English it is not my main language.
Try using Linq and File class which can let you query the file and thus provide shorter and more readable code, e.g.
using System.IO;
using System.Linq;
...
private static string FindStudentById(string id) {
return File
.ReadLines(#"C:\Text\students.txt")
.Where(line => !string.IsNullOrWhiteSpace(line)) // to be on the safe side
.Where(line => line.Split('\')[0].Trim().Equals(id.Trim()))
.FirstOrDefault() ?? $"No student with id = {id} found";
}
private static void SearchStudents() {
Console.Write("Enter student ID here: ");
string id = Console.ReadLine();
Console.WriteLine(FindStudentById(id));
}
Same for student deletion, update, etc.
private static string DeleteStudentById(string id) {
var modifiedData = File
.ReadLines(#"C:\Text\students.txt")
.Where(line => !string.IsNullOrWhiteSpace(line))
.Where(line => !line.Split('\')[0].Trim().Equals(id.Trim()))
.ToList();
File
.WriteAllLines(#"C:\Text\students.txt", modifiedData);
}
private static void DeleteStudents() {
Console.Write("Enter student ID to delete here: ");
string id = Console.ReadLine();
DeleteStudentById(id);
}
I would start by making this object oriented. Create a student class, and a collection class and implement your functionality (add/update/search) in the collection class. Some pseudo code is below to get you started
public class Student()
{
public string Id {get; set;
public string Name {get; set;}
public string Phone {get; set;}
public int Age {get; set; }
public string Grade {get; set;}
public Student()
{
}
}
public class Students: IEnumerator,IEnumerable
{
private student[] _studentlist;
int position = -1;
//Create internal array in constructor.
public Students()
{
//read you file into studentlist here
}
//IEnumerator and IEnumerable require these methods.
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
//IEnumerator
public bool MoveNext()
{
position++;
return (position < _studentlist.Length);
}
//IEnumerable
public void Reset()
{position = 0;}
//IEnumerable
public object Current
{
get { return _studentlist[position];}
}
public void Add(Student Student)
{
//Implement here
}
public void Save()
{
//persist to a file here
}
public List<Student> Search(string Id)
{
return _studentlist.Where(s => s.Id = Id);
//this could be expanded (e.g. pass in a student object and search on non empty properties)
}
}

C# error checking unique and listing price below and above

I need to check that the ISBN is unique during data entry, and to list the price lower or above for the book. I tried to display the price but instead I'm only able to display the exact price entered.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Assignment_3
{
class Program
{
public static List<Book> book = new List<Book>();
public static List<BookCategory> bc = new List<BookCategory>();
static void Main(string[] args)
{
int option;
bc.Add(new BookCategory("Comedy"));
bc.Add(new BookCategory("Horror"));
bc.Add(new BookCategory("Adventure"));
do
{
Console.WriteLine("\t\t----------------------------------------------");
Console.WriteLine("\t\t|\t1. Add new book information |");
Console.WriteLine("\t\t|\t2. Search book information |");
Console.WriteLine("\t\t|\t3. Display book information |");
Console.WriteLine("\t\t|\t4. Display book category |");
Console.WriteLine("\t\t|\t5. Exit |");
Console.WriteLine("\t\t----------------------------------------------");
Console.Write("Please choose an option : ");
option = int.Parse(Console.ReadLine());
Console.WriteLine();
switch (option)
{
case 1: Add(book,bc);
break;
case 2: Search(book,bc);
break;
case 3: Display(book, bc);
break;
case 4: Compare(bc);
break;
case 5: Environment.Exit(0);
break;
default: Console.WriteLine("You have entered an invalid option ! ");
break;
}
} while (option != 5);
Console.Read();
}
static void Add(List<Book> b, List<BookCategory> bc)
{
string title, isbn, author, bookCategory;
double price;
Console.Write("Enter the book title : ");
title = Console.ReadLine();
Console.Write("Enter the ISBN of the book : ");
isbn = Console.ReadLine();
Console.Write("Enter the author of the book : ");
author = Console.ReadLine();
Console.Write("Enter the book category <Adventure | Horror | Comedy> : ");
bookCategory = Console.ReadLine();
Console.Write("Enter the price of the book : ");
price = double.Parse(Console.ReadLine());
b.Add(new Book(title, isbn, author, bookCategory, price));
if (bookCategory == "Comedy")
{
BookCategory tempBookObj = bc.Find(delegate(BookCategory bcg)
{
return bcg.CategoryName.Equals("Comedy");
});
tempBookObj.BookNo++;
}
if (bookCategory == "Horror")
{
BookCategory tempBookObj = bc.Find(delegate(BookCategory bcg)
{
return bcg.CategoryName.Equals("Horror");
});
tempBookObj.BookNo++;
}
if (bookCategory == "Adventure")
{
BookCategory tempBookObj = bc.Find(delegate(BookCategory bcg)
{
return bcg.CategoryName.Equals("Adventure");
});
tempBookObj.BookNo++;
}
else
{
Console.WriteLine("Please enter the book category according to the list ! ");
}
}
public static void Search(List<Book> b, List<BookCategory> bc)
{
int option;
string target, target1;
double target2;
List<Book> book1 = new List<Book>();
Console.WriteLine("\t\t--------------------------------------");
Console.WriteLine("\t\t|\t1. ISBN |");
Console.WriteLine("\t\t|\t2. Book Title |");
Console.WriteLine("\t\t|\t3. Book Price |");
Console.WriteLine("\t\t|\t4. Back to main menu |");
Console.WriteLine("\t\t--------------------------------------");
Console.Write("Please choose an option : ");
option = int.Parse(Console.ReadLine());
Console.WriteLine();
switch (option)
{
case 1: Console.Write("Enter the ISBN of book to be searched : ");
target = Console.ReadLine();
Book result = b.Find(delegate(Book bk)
{
return bk.ISBN.Equals(target);
});
if (result == null)
Console.WriteLine("Product not found !");
else
Console.WriteLine(result);
break;
case 2: Console.Write("Enter the title of book to be searched : ");
target1 = Console.ReadLine();
Book result1 = b.Find(delegate(Book bk)
{
return bk.Title.Equals(target1);
});
if (result1 == null)
Console.WriteLine("Product not found !");
else
Console.WriteLine(result1);
break;
case 3: Console.Write("Enter the price of book to be searched : ");
target2 = double.Parse(Console.ReadLine());
Book result2 = b.Find(delegate(Book bk)
{
return bk.Price.Equals(target2);
});
if (result2 == null)
Console.WriteLine("Product not found !");
else
Console.WriteLine(result2);
break;
case 4:
break;
}
}
public static void Display(List<Book> b, List<BookCategory> bc)
{
b.Sort();
foreach (Book bk in b)
{
Console.WriteLine(bk.ToString());
}
}
public static void Compare(List<BookCategory> bc)
{
bc.Sort();
foreach (BookCategory bk in bc)
{
Console.WriteLine(bk.ToString());
}
}
}
}
You need to display your book details somewhat like
public static void Display(List<Book> b, List<BookCategory> bc)
{
b.Sort();
foreach (Book bk in b)
{
Console.WriteLine(bk.title + (bk.price+10).ToString());
}
}
edit the code according to your book class.
Where do you implemented the Object "Book?,
you should override there the method "ToString()" and there you can decide which value you want to display when writing "Book.Tostring();"
To get books with prices around that of the book you found:
Sort the books according to price
Locate the book you found
Get the books just before and after (but what if they have the same price?)
The coding is left as homework :-)
The big if block in your Add method is wrong. Instead of:
if (bookCategory == "Comedy") { }
if (bookCategory == "Horror") { }
if (bookCategory == "Adventure") { }
else { }
... you should have:
if (bookCategory == "Comedy") { }
else if (bookCategory == "Horror") { }
else if (bookCategory == "Adventure") { }
else { }
But even better, you can improve it by using following code (it does the same thing, but a bit shorter and imo easier to read):
switch (bookCategory)
{
case "Comedy":
case "Horror":
case "Adventure":
BookCategory tempBookObj = bc.Find(delegate(BookCategory bcg)
{
return bcg.CategoryName.Equals(bookCategory);
});
tempBookObj.BookNo++;
break;
default:
Console.WriteLine("Please enter the book category according to the list ! ");
break;
}
Also, since both your book and bc variables are static and even in the same class as other methods, there's no need to pass around those variables into all methods, since they can all access them anyway.
As for adding unique isbn, you can try something like:
do {
Console.Write("Enter the ISBN of the book : ");
isbn = Console.ReadLine();
} while (!books.Any(b => b.Isbn.Equals(isbn))) // or any other way of comparing

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