[C#] Card Utilities

AceInfinity

Emeritus, Contributor
Joined
Feb 21, 2012
Posts
1,728
Location
Canada
Here's a bunch of code I just started working on...

Code:
// Name: Card Utilities
// Copyright: (c) AceInfinity - 2013
// Description: Full code for graphics display of a card from a standard 52 card deck.
//              Includes methods and collections of Card's in various classes.
//
// IDEAS:
//     - I was thinking on creating a "Flip" state for a specific card so that you would 
//     see a back view of what a card looks like from the deck. Could be handy for games...
//
//     - I didn't feel like putting the image in the middle of the card being drawn out. 
//     But if I took this seriously, then that would be my next real update.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

#region CardDisplay
/// <summary>
/// Custom PictureBox control to display the card
/// </summary>
public class CardDisplay : PictureBox
{
	/// <summary>
	/// Fixed card dimensions.
	/// </summary>
	private const int _fixedHeight = 200;
	private const int _fixedWidth = 150;

	/// <summary>
	/// All the face values for a standard 52 card deck.
	/// (No jokers.)
	/// </summary>
	private string[] _faceValues = new string[] { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" };

	/// <summary>
	/// Card to be displayed in the PictureBox.
	/// </summary>
	private Card _displayCard;
	public Card DisplayCard
	{
		get
		{
			return _displayCard;
		}
		set
		{
			_displayCard = value;
			Invalidate();
		}
	}

	/// <summary>
	/// Need the default constructor for designer.
	/// </summary>
	public CardDisplay() : this(new Card(SUIT.Spades, VALUE.Ace)) { }

	/// <summary>
	/// For dynamic instances...
	/// </summary>
	/// <param name="card"></param>
	public CardDisplay(Card card)
	{
		_displayCard = card;
	}

	/// <summary>
	/// Paint event method for the PictureBox.
	/// </summary>
	/// <param name="e"></param>
	protected override void OnPaint(PaintEventArgs e)
	{
		base.OnPaint(e);
		Graphics g = e.Graphics;
		g.Clear(Color.White);
		g.DrawRectangle(Pens.DarkGray, Rectangle.FromLTRB(0, 0, this.Width - 1, this.Height - 1));
		PaintFace(ref g);
	}

	/// <summary>
	/// Method to paint the Suit and ID for the card.
	/// </summary>
	/// <param name="g"></param>
	private void PaintFace(ref Graphics g)
	{
		Brush color = (_displayCard.Suit == SUIT.Hearts || _displayCard.Suit == SUIT.Diamonds) ? Brushes.Red : Brushes.Black;
		string name = _faceValues[(int)_displayCard.Value];
		using (Font font = new Font(FontFamily.GenericSansSerif, 12f))
		{
			string strObj = name;
			SizeF strSize = g.MeasureString(strObj, font);
			int quad = this.Width / 4;
			g.DrawString(strObj, font, color, new PointF(quad / 2 - strSize.Width / 2, 10));
			g.DrawString(strObj, font, color, new PointF(this.Width - quad / 2 - strSize.Width / 2, this.Height - 30));

			strObj = Enum.GetName(typeof(SUIT), _displayCard.Suit);
			strSize = g.MeasureString(strObj, font);
			g.DrawString(strObj, font, color, new PointF(this.Width / 2 - strSize.Width / 2, this.Height / 2 - strSize.Height / 2));
		}
	}

	/// <summary>
	/// Keep the size consistent.
	/// I could add in resizing stuff, but the main graphics aren't even done yet, so i've decided to work with a fixed size.
	/// </summary>
	public override Size MinimumSize { get { return new Size(_fixedWidth, _fixedHeight); } }
	public override Size MaximumSize { get { return new Size(_fixedWidth, _fixedHeight); } }
}
#endregion

#region Other

#region Deck
/// <summary>
/// Class object that represents the full 52 card deck.
/// </summary>
public class Deck
{
	/// <summary>
	/// Card array property.
	/// No need for the user to modify this, unless I decide at a later date to 
	/// allow cards to be withdrawn from the deck and excluded from the pack.
	/// </summary>
	private Card[] _cards = new Card[52];
	public Card[] Cards
	{
		get { return _cards; }
	}

	/// <summary>
	/// Instantiates the full deck of cards, in an ordered state.
	/// </summary>
	public Deck()
	{
		int index = 0;
		foreach (SUIT suit in Enum.GetValues(typeof(SUIT)))
		{
			foreach (VALUE value in Enum.GetValues(typeof(VALUE)))
			{
				_cards[index++] = new Card(suit, value);
			}
		}
	}

	/// <summary>
	/// Method to shuffle the deck of cards.
	/// </summary>
	public void Shuffle()
	{
		_cards = _cards.OrderBy(card => Guid.NewGuid()).ToArray();
	}
}
#endregion

#region Hand
/// <summary>
/// Represents a hand of cards.
/// </summary>
public class Hand :
	IEnumerable<Card>, IList<Card>
{
	/// <summary>
	/// Set a maximum amount of cards that can be held in a users Hand at a time.
	/// </summary>
	public ushort MaxHandSize { get; set; }

	/// <summary>
	/// Check if we have reached the max.
	/// </summary>
	public bool HasMaxCards
	{
		get
		{
			return cards.Count == MaxHandSize;
		}
	}

	/// <summary>
	/// Container for the cards this hand is holding.
	/// </summary>
	private List<Card> cards = new List<Card>();

	#region IEnumerable<Card> Implementation
	public IEnumerator<Card> GetEnumerator()
	{
		return cards.GetEnumerator();
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return cards.GetEnumerator();
	}
	#endregion

	#region IList<Card> Implementation
	public int IndexOf(Card item)
	{
		return cards.IndexOf(item);
	}

	public void Insert(int index, Card item)
	{
		if (HasMaxCards)
		{
			throw new ArgumentException("Hand already has maximum number of cards.");
		}
		cards.Insert(index, item);
	}

	public void RemoveAt(int index)
	{
		cards.RemoveAt(index);
	}

	public Card this[int index]
	{
		get
		{
			return cards[index];
		}
		set
		{
			cards[index] = value;
		}
	}

	public void Add(Card item)
	{
		if (HasMaxCards)
		{
			throw new ArgumentException("Hand already has maximum number of cards.");
		}
		cards.Add(item);
	}

	public void Clear()
	{
		cards.Clear();
	}

	public bool Contains(Card item)
	{
		return cards.Contains(item);
	}

	public void CopyTo(Card[] array, int arrayIndex)
	{
		cards.CopyTo(array, arrayIndex);
	}

	public int Count
	{
		get { return cards.Count; }
	}

	public bool IsReadOnly
	{
		get { return false; }
	}

	public bool Remove(Card item)
	{
		return cards.Remove(item);
	}
	#endregion

	public override string ToString()
	{
		return "{ " + string.Join(", ", cards) + " }";
	}
}
#endregion

#region Card
public class Card
{
	/// <summary>
	/// After a card has been instantiated, there's no reason to change the value or suit.
	/// (We are not magicians here.)
	/// </summary>
	private readonly SUIT _suit;
	private readonly VALUE _value;

	/// <summary>
	/// Constructor that instantiates the properties of this specific card.
	/// </summary>
	/// <param name="suit"></param>
	/// <param name="value"></param>
	public Card(SUIT suit, VALUE value)
	{
		this._suit = suit;
		this._value = value;
	}

	/// <summary>
	/// Get the suit of this card.
	/// </summary>
	public SUIT Suit
	{
		get
		{
			return this._suit;
		}
	}

	/// <summary>
	/// Get the face value of this card.
	/// </summary>
	public VALUE Value
	{
		get
		{
			return this._value;
		}
	}

	public override string ToString()
	{
		return string.Format("{0} Of {1}", this._value, this._suit);
	}
}
#endregion

/// <summary>
/// Various enumerations that define the possible face values and suits that a card can use.
/// </summary>
public enum SUIT { Hearts, Diamonds, Spades, Clubs }
public enum VALUE { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace }

#endregion

So far, I've got the main structure down, I haven't tested hardly any of it other than the Deck and the Card class. The Hand class I'm just going to say it works, and if someone finds a bug in it, while be my guest to take this even further lol.

I ended up getting pretty far, I could do the rest and create the images for the suits to draw on the face of the cards, but I kinda got too tired before I decided to go at it. It is 3:20AM here (as usual, I stay up pretty late), and I am supposed to go to the gym tomorrow, but I think I'm going to have to cancel on that one.

Here's a preview of what I had for the GDI portion (not too much, but decent enough for use if someone wanted simplicity):

EEHtrvJ.gif


... Comes with no warranty, so it's staying as is for now until I decide that there's a good reason why I should continue killing more time on this :)

:thumbsup2:
 
Last edited:

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top