SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Member
    Join Date
    Dec 2008
    Posts
    21
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Need Help Implementing IComparer

    I am making a card game. I need to sort my cards first by rank (Ace, 2, Jack, etc...) and then by suit (Diamond, Spade, etc...)

    I have my enumerators setup already, with the correct value for each rank and suit.

    I am trying to write the comparer. I copied some of the code off of MSDN example. I was getting a syntax error but I fixed it.

    The code just doesn't look correct to me though. I have the rank sorting down I think, but I'm having a hard time figuring out where to add the suit sorting. Once I sort by rank I need to sort by suit as well.

    Here are my enums that show from lowest to highest how I want the cards.

    Code:
    using System;
    
    namespace CardGameFramework.Enums
    {
        public enum Rank
        {
            Ace = 1,
            Two = 2,
            Three = 3,
            Four = 4,
            Five = 5,
            Six = 6,
            Seven = 7,
            Eight = 8,
            Nine = 9,
            Ten = 10,
            Jack = 11,
            Qween = 12,
            King = 13
        }
    }
    Code:
    using System;
    
    namespace CardGameFramework.Enums
    {
        public enum Suit
        {
            Diamonds = 1,
            Spades = 2,
            Clubs = 3,
            Hearts = 4
        }
    }
    Here is my comparer code, some I copied from MSDN and then tried to modify it for my card class and not the string class MSDN was using.

    Code:
    using System;
    using System.Collections.Generic;
    using CardGameFramework.Objects;
    using CardGameFramework.Enums;
    
    namespace CardGameFramework
    {
        public class CardComparer : IComparer<Card>
        {
            public int Compare(Card x, Card y)
            {
                if (x == null)
                {
                    if (y == null)
                    {
                        // If x is null and y is null, they're
                        // equal. 
                        return 0;
                    }
                    else
                    {
                        // If x is null and y is not null, y
                        // is greater. 
                        return -1;
                    }
                }
                else
                {
                    // If x is not null...
                    if (y == null)
                    // ...and y is null, x is greater.
                    {
                        return 1;
                    }
                }
    
                if (x.CardRank == y.CardRank)
                {
                    return 0; // cards are equal
                }
                else if (x.CardRank > y.CardRank)
                {
                    return 1; // x is greater
                }
                else if (x.CardRank < y.CardRank)
                {
                    return -1; // y is greater
                }
            }
        }
    }
    My goal is when I type the following code, I want it to return a list of my card objects sorted by rank and then suit.

    Code:
    public virtual Hand Sort()
    {
        return m_cards.Sort(0, m_cards.Count, CardComparer.Compare);
    }
    If I had these 6 cards in my hand it would look like: (Aces are 1 in my game)

    Ace Diamonds, Ace Clubs, Ace Hearts, 2 Clubs, 4 Diamonds, 4 Spades
    You can see they are sorted by rank and then by suit. I need this for display on the user interface. Also, my hand validator will need the cards passed in this order so it can test for melds without errors.

    Thank You Very Much.

  2. #2
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    Question: is sorting by number and suit settable options? If you will always be doing both, just create a master enum using:

    Code:
     
    using System;
     
    namespace CardGameFramework.Enums
    {
        public enum Rank
        {
            Ace_of_Diamonds = 1,
            Two_of_Diamonds = 2,
            ....
            Queen_of_Diamonds = 12,
            King_of_Diamonds = 13
            Ace_of_Spades = 14,
            Two_of_Spades = 15,    }
            ....
    }
    The theory is that each card has only one real "value". If you want to sort by two different things, I'd implement a slightly different weight system. Perhaps use values like

    Diamond = 1
    spades = 2
    clubs = 4
    hearts = 8

    ace = 16
    two = 32

    and so on.

    m_card.weight = Rank.Diamond + Rank.Two

    ' value will be 33 and no other combo will have that same weight. you can then sort them based on that single weight value.

    EDITED:

    On reading your sorting requirements again, the following should work.

    Code:
    public enum Suit
    {
    Diamonds = 1,
    Spades = 2,
    Clubs = 4,
    Hearts = 8
    }
    public enum Rank
    {
    Ace = 16,
    Two = 32,
    Three = 64,
    Four = 128,
    Five = 256,
    Six = 512,
    Seven = 1024,
    Eight = 2048,
    Nine = 4096,
    Ten = 8192,
    Jack = 16384,
    Queen = 32768,
    King = 65536
    }
     
    m_card.weight = Suit.Diamond + Rank.Ace
    m_card.weight = Suit.Clubs + Rank.Ace
    m_card.weight = Suit.Hearts + Rank.Ace
    m_card.weight = Suit.Clubs + Rank.Two
    m_card.weight = Suit.Diamonds + Rank.Four
    m_card.weight = Suit.Spades + Rank.Four
    Add them up. You'll see the resulting values will give you the order you want. Just set the weight and sort away.

  3. #3
    SitePoint Member
    Join Date
    Dec 2008
    Posts
    21
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The first idea you have might work, althought I think it might make my code really confusing. I will have to test it out and see how it works.

    Assuming that I use that method you suggested is my CardComparer code correct? For some reason it doesn't look right to me, but I haven't been able to test it at run-time yet. I hope I can test it tonight.

  4. #4
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    Well, I really didn't take a look at that aspect. I'm not really that saavy with .NET yet, I just saw an immediate flaw with the values you were using to sort on.

    I assume your Card object has public get / set properties for Suit and Rank? If so, start by adjusting your enums like shown above and making a get only property for Weight:

    get
    return me.m_rank + me.m_suit
    end get

    I'll let a more .NET savy person look at your actual sorting code. I refuse to tell you something wrong. I would start by looking at Array.Sort however. =)

  5. #5
    SitePoint Member
    Join Date
    Dec 2008
    Posts
    21
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well, my ranking enum wasnt flawed it was designed that way being that each card's rank reflected the cards actual value during game play. The same way it does IRL for correct OOP. That way I would calculate the value of a hand by simply doing

    Code:
    foreach (Card card in Hand)
    {
        HandValue+=card.Rank;
    }
    So, I either need a new way to sort or a new way to calculate hand values.

    Edit:

    Well, I guess the entire thing is trash anyway because I won't be able to compare the cards. When I try to pass my comparer to the Sort method it wants me to specifiy the arguments for my comparer. Guess I didn't realize that before.

    Code:
    return m_cards.Sort(cc.Compare()); // No Compare method takes 0 arguments.
    So I guess I have no idea how to compare my Card class.

  6. #6
    SitePoint Member
    Join Date
    Dec 2008
    Posts
    21
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I found another sort method, I am going to try and use but I don't understand why the guy is writing the code in this way, he is passing in two Person objects as arguments, and then converting the Person objects to a Person several times. Is this really neeeded? It seems just like a waste of time. We already know that only a Person can be passed as a Person argument.

    It looks like he is also checking to see if a Person is a Person, it just seems stupid. So I must be missing something.

    Code:
    static public int Compare( Person x, Person y )
    {
        int result = 1;
        if (x != null && x is Person &&
            y != null && y is Person)
        {
            Person personX = (Person)x;
            Person personY = (Person)y;
            result = personX.CompareTo( personY );
        }
        return result;
    }
    http://www.csharp411.com/c-stable-sort/

  7. #7
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    I think before anybody can help ( I know it's true in my case ) we'd need to see more of your code, like some of your Card object code. I'm not sure using a game mechanic is the best idea for sorting. Differences in game mechanics and code mechanics often cause little problems like this. I'm afriad I can't really help based on what little I know about your app.

  8. #8
    SitePoint Mentor NightStalker-DNS's Avatar
    Join Date
    Jul 2004
    Location
    Cape Town, South Africa
    Posts
    2,880
    Mentioned
    48 Post(s)
    Tagged
    0 Thread(s)
    Well. How I see it you have to options.

    Note: Im not infront of my PC now, so not 100% sure on syntax. So just check with intellisence.

    1. Linq and lambda:
    List<Card> deck = BLL.getCards();
    deck = deck.OrderByDescending(o => o.Rank).ThenBy(o => o.Suit);

    2. This option: http://www.codeproject.com/KB/cs/GenericSorter.aspx

    I hope this helps u


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •