Beginnings of a Poker hand classifier For practicing/learning object orientation, I made a Card class and am practicing doing stuff with it such as shuffling decks and dealing hands etc...

I have a method that receives a list item which essentially is a hand of 5 cards then tells the user how about the hand such as pairs and three of a kind however it feels incredibly sloppy and would like to know if it's improvable.

private static string CheckHand(List&lt;Card&gt; hand)
{
    string[] tempnames = { hand[0].Face, hand[1].Face, hand[2].Face, hand[3].Face, hand[4].Face };         
    int sameCardCount = 0;     

    for (int i = 0; i &lt; hand.Count; i++)
    {
        for (int k = 0; k &lt; hand.Count; k++)
        {
            if (k == i) { }
            else if (tempnames[i] == hand[k].Face)
            {                                       
               sameCardCount++;
            }
        }
    }
    switch (sameCardCount)
    {
        case 12:
        return "you have four of a kind!";
        case 6:
        return "you have three of a kind!";
        case 4:                  
        return "you have two pairs!";  
        case 2:   
        return "you have a pair!";
        default:
        return "nothing special here..";
    }
}


The card object and enum suit is like so:

class Card
{
    public string Face { get; set; }
    public Suit Suitc { get; set; }
    public Card(Suit suit,string face)
    {
        Face = face;
        Suitc = suit;
    }

    public override string ToString()
    {
        string card = "(" + Face + " " + Suitc + ")";
        return card;
    }
}
enum Suit
{
    CLUB, DIAMOND, HEART, SPADE
}


As far as I can test, it works as intended. But with the double loop, the return values are a bit messy in my opinion. How would you have done it?

Note: you do not have to provide extracts of code if you don't wish to. I'm just trying to help myself improve my problem solving.
Much of your code can be made shorter and more clear with LINQ:

string[] tempnames = { hand[0].Face, hand[1].Face, hand[2].Face, hand[3].Face, hand[4].Face };         


vs

var faces = hand.Select(c =&gt; c.Face).ToArray();


But we actually don't need this at all, because your main algorithm can be made more clear with LINQ as well. What do you want?  To divide the cards up into groups based on their face value.  So do that!

var cardCounts = (from card in hand         // We're processing each card
                 group card by card.Face    // make a sequence of groups of cards with the same face
                 into g                     // process each group 
                 let count = g.Count()      // get the size of each group
                 orderby descending count   // sort the groups by size, big to small
                 select count).Take(2).ToList();  // get the top two sizes


Before you read on: Why did I only take the highest two counts? 

And now you can just read off the results:

switch(cardCounts[0]) 
{
  case 1: return "nothing";
  case 2: return cardCounts[1] == 1 ? "one pair" : "two pair";
  case 3: return cardCounts[1] == 1 ? "three of a kind" : "full house";
  case 4: return "four of a kind";
  default: Debug.Fail("How'd we get here?"); return "";
}


LINQ make the code read more like its meaning rather than a bunch of loops and counters that seem completely disconnected from the domain at hand. What are you doing logically?  Grouping the cards by face value and counting how many cards are in each group.  So make the code actually do that.

Remember, your goal here is to correctly implement the rules. The rules do not say "consider all ordered pairs of cards; assign one point for each identical card in that set of pairs. If the point total is 12 then..." and so on, but that's what you wrote.  Which is more likely to be correct, code that resembles the logic of the rules, or code that does some completely other thing that you hope is equivalent to the rules? Which do you suppose will be easier to maintain?

Exercise: Now add flushes, straights, and straight flushes. Can you use LINQ?

Exercise: Come up with a better representation for the value of a hand other than a string describing it

Exercise: Make a class for hands. What operations do you need to perform on hands?

Exercise: Cards don't change their kind, but you've modeled them as having setters. Make the card type an immutable struct, not a mutable class.

Exercise: Implement IComparable&lt;Card&gt; on cards. 

Exercise: Given two hands, which, if either, is the winning hand?  Implement IComparable&lt;Hand&gt; on Hand. Note that you'll need more than just the kind of hand it is! Suppose there are two hands, both are two pair, and both are pair of kings, pair of queens. One of them still could win.  Read the rules of poker carefully; that's your specification. Again, try to make the code read like the rules.

Exercise: Given a sequence of cards, generate all possible five-card hands.  The signature of your method should be static IEnumerable&lt;Hand&gt; AllHands(IEnumerable&lt;Card&gt; cards).  If there are fewer than 5 cards in the sequence then clearly the resulting sequence should be empty.  If there are exactly 5 then you should get exactly one hand.  If there are 6 cards then you should get 5 hands. If there are 7 cards then how many hands should you get?

Exercise: given a sequence of 7 cards, find the highest 5-card hand in it.

Exercise: given n two-card hands and five community cards, describe how to divide the pot. Note that you have to represent ties somehow.  Again, remember, you are implementing the rules of poker, and those include ties. 

Exercise: What if there are multiple pots, due to an all-in situation? Now how to divide the pots?

Exercise: Implement the rest of the rules of poker: ante, betting, raising, etc. 

Exercise: Write an AI that plays poker, and a user interface that lets humans play against the AI.