I am creating a poker system and I am currently streamlining my hand calculator.
The following code works:
public enum CARDS
{
None = 0,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace
};
public enum SUITS
{
None = 0,
Diamonds,
Clubs,
Hearts,
Spades
};
public class Card
{
public CARDS Val { get; set; }
public SUITS Suit { get; set; }
}
public class IntIndex
{
public int Count { get; set; }
public int Index { get; set; }
}
static void Test()
{
List<Card> cardList = new List<Card>();
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Two });
cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Four });
cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Five });
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Six });
cardList.Add(new Card { Suit = SUITS.Spades, Val = CARDS.Six });
cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Seven });
cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Eight });
// I have a processor that iterates through the above card list and creates
// the following array based on the Card.Val as an index
int[] list = new int[] {0,0,0,1,1,2,1,1,0,0,1,0,0,0};
List<IntIndex> indexList =
list.Select((item, index) => new IntIndex { Count = item, Index = index })
.Where(c => c.Count > 0).ToList();
List<int> newList = (from i in indexList
join j in indexList on i.Index equals j.Index + 1
where j.Count > 0
select i.Index).ToList();
// Add the previous index since the join only works on n+1
// Note - Is there a way to include the first comparison card?
newList.Insert(0, newList[0] - 1);
// Nice! - got my straight card list
List<CARDS> cards = (from l in newList
select (CARDS)l).ToList();
}
However, I want to make it more compact as in:
static void Test()
{
List<Card> cardList = new List<Card>();
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Two });
cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Four });
cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Five });
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Six });
cardList.Add(new Card { Suit = SUITS.Spades, Val = CARDS.Six });
cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Seven });
cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Eight });
List<Card> newList1 = (from i in cardList
join j in cardList on i.Val equals j.Val + 1
select i).ToList();
// Add the previous index since the join only works on n+1
// Similar to: newList1.Insert(0, newList1[0] - 1);
// However, newList1 deals with Card objects so I need
// To figure how to get the previous, non-duplicate card
// from the original cardList (unless there is a way to return the
// missing card!)
}
The problem is that the Sixes are being repeated. Distinct as well as a custom compare function does not work since this will break the n+1 join clause.
Another problem is with the following card list:
List<Card> cardList = new List<Card>();
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Two });
cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Three });
cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Five });
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Six });
cardList.Add(new Card { Suit = SUITS.Spades, Val = CARDS.Six });
cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Seven });
cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Eight });
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Jack });
I get a return list of 3Hearts, 6Diamond, 7Hearts, 8Hearts since 2 and 3 are consecutive.
What I really want is a list that returns consecutive cards of 5 or greater, or better yet, the top 5 cards of a continuous sequence. So the above list will return empty since there are no 5 consecutive cards in the input list.
If you are interested in getting the subset of cards from cardList that has the highest range of sequential card values, regardless of suit, consider this approach.
//Extension method to find a subset of sequential consecutive elements with at least the specified count of members.
//Comparisions are based on the field value in the selector.
//Quick implementation for purposes of the example...
//Ignores error and bounds checking for purposes of example.
//Also assumes we are searching for descending consecutive sequential values.
public static IEnumerable<T> FindConsecutiveSequence<T>(this IEnumerable<T> sequence, Func<T, int> selector, int count)
{
int start = 0;
int end = 1;
T prevElement = sequence.First();
foreach (T element in sequence.Skip(1))
{
if (selector(element) + 1 == selector(prevElement))
{
end++;
if (end - start == count)
{
return sequence.Skip(start).Take(count);
}
}
else
{
start = end;
end++;
}
prevElement = element;
}
return sequence.Take(0);
}
//Compares cards based on value alone, not suit.
//Again, ignores validation for purposes of quick example.
public class CardValueComparer : IEqualityComparer<Card>
{
public bool Equals(Card x, Card y)
{
return x.Val == y.Val ? true : false;
}
public int GetHashCode(Card c)
{
return c.Val.GetHashCode();
}
}
Given the above, the approach would be to first sort the cards based on the value of the card, not the suit, giving you the cards in descending order. Then create a subset of the distinct cards, again based only on card value, not suit. Then call into FindConsecutiveSequence specifying the Val property for comparison and the amount of elements you need for a valid sequence.
//Sort in descending order based on value of the card.
cardList.Sort((x,y) => y.Val.CompareTo(x.Val));
//Create a subset of distinct card values.
var distinctCardSet = cardList.Distinct(new CardValueComparer());
//Create a subset of consecutive sequential cards based on value, with a minimum of 5 cards.
var sequentialCardSet = distinctCardSet.FindConsecutiveSequence(p => Convert.ToInt32(p.Val), 5);
I think this should cover what you asked in the question and give you something to build on. However, if this if for poker, this logic will fail in the case where Ace can be a low value -> {A,2,3,4,5}. I didn't see mention of Ace specific logic needed, so perhaps you handle it outside of the scope of the question.
Order the Cards by Number then Take 1 and Skip 3 of them to select what you want.
Is this what you want?
First a random list of suits, but sequential list of cards values
Random random = new Random((int)(DateTime.Now.ToBinary() % Int32.MaxValue));
List<Card> hand = new List<Card>();
for(int card = (int)CARDS.Five;card <= (int)CARDS.Nine;card++)
{
SUIT suit = (SUITS)(random.Next(4)+1);
hand.Add(new Card { Suit = suit, Val = (CARDS)card });
}
Or a sequential list of suits would be...
for(int card = (int)CARDS.Five, int suit = (int)SUITS.Diamonds;card <= (int)CARDS.Nine;card++, suit++)
{
if(suit > (int)SUITS.Spades)
suit = (int)SUITS.Diamonds;
hand.Add(new Card { Suit = (SUITS)suit, Val = (CARDS)card });
}
Use the Aggregate method. You can modify the example code below to return various lengths of card lists, and change the while clause to check for the amount of cards that must match. (e.g. my version checks for Count == 5, you could check for Count >= 5, etc.)
public class Card {
public CARDS Val { get; set; }
public SUITS Suit { get; set; }
// added ToString for program below
public override string ToString() {
return string.Format("{0} of {1}", Val, Suit);
}
}
class Program {
static IEnumerable<Card> RandomList(int size) {
var r = new Random((int)DateTime.Now.Ticks);
var list = new List<Card>();
for (int i = 0; i < size; i++) {
list.Add(new Card {
Suit = (SUITS)r.Next((int)SUITS.Diamonds, (int)SUITS.Spades),
Val = (CARDS)r.Next((int)CARDS.Two, (int)CARDS.Ace)
});
}
return list.OrderBy(c => c.Val);
}
// generates a random list of 5 cards untill
// the are in sequence, and then prints the
// sequence
static void Main(string[] args) {
IEnumerable<Card> consecutive = null;
do {
// generate random list
var hand = RandomList(5);
// Aggreate:
// the passed in function is run for each item
// in hand. acc is the accumulator value.
// It is passed in to each call. The new List<Card>()
// parameter is the initial value of acc when the lambda
// is called on the first item in the list
// in the lambda we are checking to see if the last
// card in the accumulator value is one less
// than the current card. If so, add it to the
// accumulator, otherwise do not.
consecutive = hand.Aggregate(new List<Card>(), (acc, card) => {
var size = acc.Count != 0
? ((int)card.Val) - ((int)acc[acc.Count - 1].Val)
: 1;
if (size == 1)
acc.Add(card);
return acc;
});
} while (consecutive.Count() != 5);
foreach (var card in consecutive) {
Console.WriteLine(card);
}
Console.ReadLine();
}
}
The following method should get the best straight hand when supplied with seven cards (including the edge case of A-5), but I haven't tested it thoroughly.
The key point is that if you sort the cards into descending order and remove any duplicate values, there are only a few possible ways for the straight to be arranged (and you only need to check the extremities):
If the first and fifth cards are four apart, they represent the highest straight (since we know the cards between them have no duplicate values).
The same is true, in order, for the second and sixth cards and for the third and seventh cards (if there are that many unique values left).
The only other possibility is if we have an Ace at the start of the sorted list and the cards Five to Two at the end, representing a A-5 straight.
Here's the code:
public static IEnumerable<Card> GetBestStraight(IEnumerable<Card> sevenCards)
{
if (sevenCards.Count() != 7)
{
throw new ArgumentException("Wrong number of cards", "sevenCards");
}
List<Card> ordered = sevenCards.OrderByDescending(c => c.Val).ToList();
List<Card> orderedAndUnique = ordered.Where((c, i) => i == 0 || ordered[i].Val != ordered[i - 1].Val).ToList();
if (orderedAndUnique.Count < 5)
{
// not enough distinct cards for a straight
return Enumerable.Empty<Card>();
}
if (orderedAndUnique[0].Val == orderedAndUnique[4].Val + 4)
{
// first five cards are a straight
return orderedAndUnique.Take(5);
}
else if (5 < orderedAndUnique.Count && orderedAndUnique[1].Val == orderedAndUnique[5].Val + 4)
{
// next five cards are a straight
return orderedAndUnique.Skip(1).Take(5);
}
else if (6 < orderedAndUnique.Count && orderedAndUnique[2].Val == orderedAndUnique[6].Val + 4)
{
// last five cards are a straight
return orderedAndUnique.Skip(2).Take(5);
}
// if there's an A-5 straight, the above won't have found it (because Ace and Two are not consecutive in the enum)
if (orderedAndUnique[0].Val == CARDS.Ace && orderedAndUnique[orderedAndUnique.Count - 4].Val == CARDS.Five)
{
return orderedAndUnique.Where(c => c.Val == CARDS.Ace || c.Val <= CARDS.Five);
}
return Enumerable.Empty<Card>();
}
Stupid is as stipid does! Whay was I so worried about using LINQ when the quickest soulution was a simple bit mask:
List<Card> cardList = new List<Card>();
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = RANK.Two });
cardList.Add(new Card { Suit = SUITS.Hearts, Val = RANK.Three });
cardList.Add(new Card { Suit = SUITS.Clubs, Val = RANK.Five });
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = RANK.Seven });
cardList.Add(new Card { Suit = SUITS.Hearts, Val = RANK.Four });
cardList.Add(new Card { Suit = SUITS.Clubs, Val = RANK.King });
cardList.Add(new Card { Suit = SUITS.Diamonds, Val = RANK.Ace });
int card = 0;
foreach (Card c in cardList)
{
card |= 1 << (int)c.Val - 1;
}
bool isStraight = false;
RANK high = RANK.Five;
int mask = 0x1F;
while (mask < card)
{
++high;
if ((mask & card) == mask)
{
isStraight = true;
}
else if (isStraight)
{
--high;
break;
}
mask <<= 1;
}
// Check for Ace low
if ((!isStraight) && ((0x100F & card) == 0x100F))
{
isStraight = true;
high = RANK.Five;
}
return card;
Related
This is my first time using C#. I have to convert an old project from Java. The old project works, but when I attempted to convert it, something went wrong? The Card class sets the default card to the Ace of Spades, but it is displaying Ace of Clubs. Ace and Clubs are each the first listed of the enums so I guess it is not using the default?
Since it is displaying the same card I thought it would be something wrong with my shuffle method..but I am unsure at this point.
There is a Card, Deck, and Hand class. Then Enums for Suit and Face.
UPDATE: I believe the error is in the method directly below? I need to figure out how to use the 'n' in c#. It is needed in a different class.
In Java I had it as:
public Card(int n)
{
face = Face.values()[n % 13];
suit = Suit.values()[n % 4];
} //end Card (int n) method
c#:
public Card(int n) //??
{
var face = (Face) 13;
var suit = (Suit) 4;
}
The code above is in the Card class? I know that is not too helpful, but the only other way it to post ALL of the code here.
//Some of the Deck class
public void Shuffle()
{
Random ran = new Random();
for (int nextCard = 0; nextCard < deck.Length; nextCard++)
{
Card hold = deck[nextCard];
int random = ran.Next(deck.Length);
deck[nextCard] = deck[random];
deck[random] = hold;
}
}
public Card DealACard()
{
if (nextCard > 51)
{
return null;
}
return deck[nextCard++];
}
public Hand DealAHand(int handSize)
{
Hand hand = new Hand(handSize);
for (int i = 0; i < handSize; i++)
{
hand.AddCard(DealACard());
}
return hand;
}
//Some of the Hand Class
public void AddCard(Card card)
{
hand[cardsInHand] = card;
cardsInHand++;
}
public override string ToString()
{
String handToString = ""; //string to hold display format
//for loop to display each card in a hand
for (int n = 0; n < cardsInHand; n++)
{
handToString += hand[n].ToString() + "\n";
}
return handToString;
}
// Driver Class
Deck deck1 = new Deck();
int cardsToGet = 53;
do
{
Console.Write("How many cards are in one hand? ");
int handSize = Convert.ToInt32(Console.ReadLine());
// int handSize = Console.Read();
Console.Write("How many players are playing? ");
int players = Convert.ToInt32(Console.ReadLine());
cardsToGet = handSize * players;
if (cardsToGet < 53) // if to shuffle deck and display players' hands
{
deck1.Shuffle();
for (int i = 0; i < players; i++) // displays each players hand
{
Console.WriteLine("\nPlayer " + (i + 1) + ":");
Console.WriteLine(deck1.DealAHand(handSize));
}
}
else
{
Console.WriteLine("\nThere are not enough cards in the deck to deal " + players + " hands of " + handSize + " cards. Try again.\n");
}
}
while (cardsToGet > 52);
It is suppose to ask for a number of cards per hand and a number of players then displays a hand for each player without duplicating cards. Currently, it fills every players hand with Ace of Clubs. There are no errors showing.
Now that you've updated your question, this is answerable. The mistake is in your Card constructor, which no matter the value of n that you pass in, creates every card with the Face with value 13 and the Suit with value 4. You have the right method for turning an int into a Face or Suit enum (just cast it), so you just need to do the modulo operation like your Java version did:
public Card(int n)
{
var face = (Face) n % 13;
var suit = (Suit) n % 4;
}
Well, almost. The var keyword in C# just creates a local variable that's not visible outside the scope it's declared in: in this case, the constructor. What you meant to do is assign values to instance properties of your Card class. You haven't shown us what those properties are named, but I'm going to assume they're named Face and Suit (with initial uppercase as is C# naming convention); rename as appropriate:
public Card(int n)
{
this.Face = (Face) n % 13;
this.Suit = (Suit) n % 4;
}
And now your cards should all be different, rather than all being the ace of clubs.
Hello TJ and welcome to S/O, coming from other languages can be a learning curve. Same as if I switched to Java. I quickly threw this together to introduce working with lists and classes within C#. Not perfect, but does what you are looking to get at. Hope it helps. I originally wrote this with C# via a WPF application vs Console app, but the core is all the same (only thing that would be different is the "MessageBox.Show()" that shows each hand vs the Console output which I also included.
I am notorious for commenting through my code and hope this all (or most of it) makes sense as you dive into C#...
I'm starting with enums for the card faces and suits.
public enum CardFace
{
Two = 0,
Three = 1,
Four = 2,
Five = 3,
Six = 4,
Seven = 5,
Eight = 6,
Nine = 7,
Ten = 8,
Jack = 9,
Queen = 10,
King = 11,
Ace = 12
}
public enum CardSuit
{
Hearts = 0,
Clubs = 1,
Diamonds = 2,
Spades = 3
}
Next, a class to represent a single card
public class SingleCard
{
public CardFace Face { get; set; }
public CardSuit Suit { get; set; }
// place-holder for randomizing cards
public int RndNumber { get; set; }
// return the name of the card based on it's parts as single string
public string NameOfCard { get { return $"{Face} of {Suit}"; } }
}
Now, the class for building the initial deck of cards, shuffling, dealing and displaying the cards (of the entire deck, or of the individual hands)
public class DeckOfCards
{
public List<SingleCard> SingleDeck { get; private set; } = new List<SingleCard>();
public List<SingleCard> ShuffledDeck { get; private set; }
// create a single random generator ONCE and leave active. This to help prevent
// recreating every time you need to shuffle and getting the same sequences.
// make static in case you want multiple decks, they keep using the same randomizing object
private static Random rndGen = new Random();
public DeckOfCards()
{
// build the deck of cards once...
// Start going through each suit
foreach (CardSuit s in typeof(CardSuit).GetEnumValues())
{
// now go through each card within each suit
foreach (CardFace f in typeof(CardFace).GetEnumValues())
// Now, add a card to the deck of the suite / face card
SingleDeck.Add(new SingleCard { Face = f, Suit = s });
}
// so now you have a master list of all cards in your deck declared once...
}
public void ShuffleDeck()
{
// to shuffle a deck, assign the next random number sequentially to the deck.
// don't just do random of 52 cards, but other to prevent duplicate numbers
// from possibly coming in
foreach (var oneCard in SingleDeck)
oneCard.RndNumber = rndGen.Next(3901); // any number could be used...
// great, now every card has a randomized number assigned.
// return the list sorted by that random number...
ShuffledDeck = SingleDeck.OrderBy( o => o.RndNumber).ToList();
}
public void DisplayTheCards( List<SingleCard> theCards )
{
// show the deck of cards, or a single person's hand of cards
var sb = new StringBuilder();
foreach (var c in theCards)
sb = sb.AppendLine( c.NameOfCard );
MessageBox.Show(sb.ToString());
}
public void ConsoleDisplayTheCards(List<SingleCard> theCards)
{
// show the deck of cards, or a single person's hand of cards
foreach (var c in theCards)
Console.WriteLine(c.NameOfCard);
}
public List<List<SingleCard>> DealHands( int Players, int CardsPerHand )
{
// create a list of how many hands to be dealt...
// each player hand will consist of a list of cards
var Hands = new List<List<SingleCard>>(Players);
// prepare every players hand before dealing cards
for (var curPlayer = 0; curPlayer < Players; curPlayer++)
// each player gets their own list of cards
Hands.Add( new List<SingleCard>());
// prepare card sequence to deal
var nextCard = 0;
// loop for as many cards per hand
for (var oneCard = 0; oneCard < CardsPerHand; oneCard++)
{
// loop every player gets a card at a time vs one player gets all, then next player
for (var curPlayer = 0; curPlayer < Players; curPlayer++)
// add whatever the next card is to each individual's hand
Hands[curPlayer].Add(ShuffledDeck[nextCard++]);
}
return Hands;
}
}
I did not include the input of getting how many players, how many cards as you already had that. I also did not validate total cards to be dealt as you had that too. HTH
I'm trying to create a deck of 52 cards with the 4 suits: spades, hearts, clubs, and diamonds. I tried to create this for loop in my Deck class but seem to be running into some problems regarding actually getting the program to do what I want. I'm thinking maybe I could do 4 for loops as the assignment hinted at, but is it possible to use if/else-ifs to create 4 suits within the deck?
class Deck
{
private Card[] cards;
public Deck()
{
cards = new Card[52];
int check = 0;
for (int suitVal = 1; suitVal < 4; suitVal++)
{
for (int rankVal = 1; rankVal < 14; rankVal++)
{
if(suitVal == 1)
{
cards[check] = new Card(rankVal, "Spades");
}
else if (suitVal == 2)
{
cards[check] = new Card(rankVal, "Hearts");
}
else if (suitVal == 3)
{
cards[check] = new Card(rankVal, "Clubs");
}
else if (suitVal == 4)
{
cards[check] = new Card(rankVal, "Diamonds");
}
}
}
}
Yes, it is possible.
There are 13 cards and 4 suits. The idea is that for each suit, you create 13 cards with of said suit. The pseudo code is pretty much what you have already got:
for each of the four suits
loop 13 times for said suit
Here are the problems with your code:
1- Your check variable is never incremented, so you always overwrite the card on the position 0; It should increment after every card inserted (inner loop)
2- Your outter loop only runs 3 times (i = 1, i = 2, i = 3), and there are 4 suits.
Let me know if you need more help.
You could do it these ways:
class Deck
{
private Card[] cards;
public Deck()
{
cards =
new [] { "Spades", "Hearts", "Clubs", "Diamonds", }
.SelectMany(
suit => Enumerable.Range(1, 13),
(suit, rank) => new Card(rank, suit))
.ToArray();
}
}
Or:
class Deck
{
private Card[] cards;
public Deck()
{
var query =
from suit in new [] { "Spades", "Hearts", "Clubs", "Diamonds", }
from rank in Enumerable.Range(1, 13)
select new Card(rank, suit);
cards = query.ToArray();
}
}
Or:
class Deck
{
private Card[] cards;
public Deck()
{
cards = new Card[52];
var index = 0;
foreach (var suit in new [] { "Spades", "Hearts", "Clubs", "Diamonds", })
{
for (var rank = 1; rank <= 13; rank++)
{
cards[index++] = new Card(rank, suit);
}
}
}
}
I have to implement a poker game using Test-Driven Development. Now I have to check if the given hand contains straight flush. So I have to check the enumerations of each card if is greater with one than the previous one. Let me show some code.
public bool IsStraightFlush(IHand hand)
{
var sortedCards = hand.Cards.OrderBy(card => card.Face).ThenBy(card => card.Suit);
}
Each card is declaring by two parameters of enums: public Card(CardFace face, CardSuit suit)
CardFace and CardSuits are enums.
Here's what I wrote for now - I sorted the given hand as parameter consisted of five cards. I ordered first by face, then by suit. Now I have to know how to check if the next card of the hand has the CardFace enum + 1 than the current one. Here's the enumeration for CardFace.
public enum CardFace
{
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
Ten = 10,
Jack = 11,
Queen = 12,
King = 13,
Ace = 14
}
I hope this will work :
public bool IsStraightFlush(IHand hand)
{
var sortedCards = hand.Cards.OrderBy(card => card.Face).ThenBy(card => card.Suit).ToList();
bool straightFlush = true;
for (int i = 1; i < sortedCards.Count(); i++)
{
if ((int)sortedCards[i].Face != (int)sortedCards[i - 1].Face + 1)
{
straightFlush = false;
break;
}
}
return straightFlush;
}
This might help you, cast you sequence to int, then check that next element -1 equals current:
static bool CheckForSequence(List<int> input)
{
input.Sort();
var result = true;
for (int i = 0; i < input.Count - 1; i++)
{
result = input[i] == input[i + 1] - 1;
if (!result)
break;
}
return result;
}
And one more solution, you still need to cast ti int, but it much shorter:
static bool CheckForSequence(List<int> input)
{
return !input.OrderBy(p => p).Select((p, i) => p - i).Distinct().Skip(1).Any();
}
In this case, if collection sequential, difference between item and index will be same for all elements.
Try using a group by and then checking that there is a single group and all the cars within it are sequential.
public bool IsStraightFlush(IHand hand)
{
var sortedCards = from c in hand.Cards
group c by c.Suit into d
select new
{
Suit = d.Key,
Cards = d.OrderBy(x => x.Face)
};
// all cards are the same suit
if(sortedCards.Count() == 1)
{
Card previousCard = null;
foreach (var card in sortedCards.First().Cards)
{
if(previousCard != null && (card.Face - previousCard.Face > 1))
{
return false;
}
previousCard = card;
}
return true;
}
return false;
}
void Main()
{
var hand = new Hand
{
Cards = new List<Card>
{
new Card { Face = CardFace.Two, Suit = CardSuit.Clubs },
new Card { Face = CardFace.Three, Suit = CardSuit.Clubs },
new Card { Face = CardFace.Four, Suit = CardSuit.Clubs },
new Card { Face = CardFace.Five, Suit = CardSuit.Clubs },
new Card { Face = CardFace.Six, Suit = CardSuit.Clubs },
}
};
Console.WriteLine(IsStraightFlush(hand));
}
I want to count all combinations of poker cards that a player can get in one hand and display all those combinations. I don't care about how many pairs, full houses etc. are there. I just want to count all possible hands that a player can get. So, one hand is made of 5 cards, there must be 4 colors (suits) and one suit must repeat. Maximum is that 4 numbers are same, number of 5th card must be different. Correct result of all possible hand combinations must be 2598960 (52 above 5 is 2598960). I just need to get correct result using my code, but I don't know how to write the algorithm.
I have card.cs class:
class card
{
private int number;
private char suit;
public card(int _number, char _suit)
{
this.number = _number;
this.suit = _suit;
}
public int Number
{
get{return this.number;}
set{this.number = value;}
}
public char Suit
{
get { return this.suit; }
set { this.suit = value; }
}
}
and in Program.cs class, I have Main and this code:
static void Main(string[] args)
{
char[] suits = { '\u2660', '\u2663', '\u2665', '\u2666' }; //Spades, Clubs, Hearts, Diamonds
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
int cnt = 0;
List<card> deck = new List<card>();
//making deck
foreach (char suit in suits)
{
foreach (int number in numbers)
{
deck.Add(new card(number, suit));
}
}
foreach (card first in deck)
{
foreach (card second in deck)
{
if (second.Number != first.Number)
{
foreach (card third in deck)
{
if (third.Number != second.Number && third.Number != first.Number)
{
foreach (card fourth in deck)
{
if (fourth.Number != third.Number && fourth.Number != second.Number && fourth.Number != first.Number)
{
foreach (card fifth in deck)
{
if (fifth.Suit != first.Suit && fifth.Suit != second.Suit && fifth.Suit != third.Suit && fifth.Suit != fourth.Suit)
{
//Console.WriteLine("{0}{1} {2}{3} {4}{5} {6}{7} {8}{9}", first.Number, first.Suit, second.Number, second.Suit, third.Number, third.Suit, fourth.Number, fourth.Suit, fifth.Number, fifth.Suit);
cnt++;
}
}
}
}
}
}
}
}
}
Console.WriteLine("Combinations: {0}", cnt);//Result must be: 2598960
}
Well, as much as I appreciate what you're doing, I find this easier to read:
int count = 0;
int cards_amount = 52;
for (var first = 0; first < cards_amount-4; first++)
for (var second = first + 1; second < cards_amount-3; second++)
for (var third = second+1; third < cards_amount-2; third++)
for (var fourth = third+1; fourth < cards_amount-1; fourth++)
for (var fifth = fourth+1; fifth < cards_amount; fifth++)
count++;
Instead of looking at all the duplicates, and the if this card is different from the previous, what I do is: Put all cards in a row. Select the first, and then the second from the remaining, and then the third from the remaining ... and so on.
This way, you don't need to check for multiples, and you get your right answer :)
Edit:
As for the comment ... Just add this line after you initialize your list:
var deck_array = deck.ToArray();
You might want to do this on your class card:
public override string ToString() {
// have this print your card number & suit
}
And then, just change the count++; line with this:
{
count ++;
Console.WriteLine("{0},{1},{2},{3},{4}", deck_array[first], deck_array[second],
deck_array[third] , deck_array[fourth] , deck_array[fifth] );
}
Solved ... (now your cards know how to print themselves, and you're just printing the hand at the end.
I have an unordered list that can look something like this:
1
2.2
1.1.1
3
When i sort the list, 1.1.1 becomes greater than 3 and 2.2, and 2.2 becomes greater than 3.
This is because Double.Parse removes the dots and makes it a whole number.
This is the method i use to sort with:
public class CompareCategory: IComparer<Category>
{
public int Compare(Category c1, Category c2)
{
Double cat1 = Double.Parse(c1.prefix);
Double cat2 = Double.Parse(c2.prefix);
if (cat1 > cat2)
return 1;
else if (cat1 < cat2)
return -1;
else
return 0;
}
}
How can i fix this?
Thanks
Are these version #s by chance? Can you use the Version class? It sorts each part as you seem to want, although it only works up to 4 parts. I would not recommend parsing into a numeric value like you are doing.
It has an IComparable interface. Assuming your inputs are strings, here's a sample:
public class CompareCategory: IComparer<Category>
{
public int Compare(Category c1, Category c2)
{
var cat1 = new Version(c1.prefix);
var cat2 = new Version(c2.prefix);
if (cat1 > cat2)
return 1;
else if (cat1 < cat2)
return -1;
else
return 0;
}
}
If you need something with more than 4 "parts", I think I would create a comparer which split the strings at the dots, and then parse each element as an integer and compare them numerically. Make sure to consider cases like 1.002.3 and 1.3.3 (what do you want the sort order to be?).
Update, here is a sample of what I mean. Lightly tested:
public class CategoryComparer : Comparer<Category>
{
public override int Compare(Category x, Category y)
{
var xParts = x.prefix.Split(new[] { '.' });
var yParts = y.prefix.Split(new[] { '.' });
int index = 0;
while (true)
{
bool xHasValue = xParts.Length > index;
bool yHasValue = yParts.Length > index;
if (xHasValue && !yHasValue)
return 1; // x bigger
if (!xHasValue && yHasValue)
return -1; // y bigger
if (!xHasValue && !yHasValue)
return 0; // no more values -- same
var xValue = decimal.Parse("." + xParts[index]);
var yValue = decimal.Parse("." + yParts[index]);
if (xValue > yValue)
return 1; // x bigger
if (xValue < yValue)
return -1; // y bigger
index++;
}
}
}
public static void Main()
{
var categories = new List<Category>()
{
new Category { prefix = "1" },
new Category { prefix = "2.2" },
new Category { prefix = "1.1.1" },
new Category { prefix = "1.1.1" },
new Category { prefix = "1.001.1" },
new Category { prefix = "3" },
};
categories.Sort(new CategoryComparer());
foreach (var category in categories)
Console.WriteLine(category.prefix);
}
Output:
1
1.001.1
1.1.1
1.1.1
2.2
3
public class CodeComparer : IComparer<string>
{
public int Compare(string x, string y)
{
var xParts = x.Split(new char[] { '.' });
var yParts = y.Split(new char[] { '.' });
var partsLength = Math.Max(xParts.Length, yParts.Length);
if (partsLength > 0)
{
for (var i = 0; i < partsLength; i++)
{
if (xParts.Length <= i) return -1;// 4.2 < 4.2.x
if (yParts.Length <= i) return 1;
var xPart = xParts[i];
var yPart = yParts[i];
if (string.IsNullOrEmpty(xPart)) xPart = "0";// 5..2->5.0.2
if (string.IsNullOrEmpty(yPart)) yPart = "0";
if (!int.TryParse(xPart, out var xInt) || !int.TryParse(yPart, out var yInt))
{
// 3.a.45 compare part as string
var abcCompare = xPart.CompareTo(yPart);
if (abcCompare != 0)
return abcCompare;
continue;
}
if (xInt != yInt) return xInt < yInt ? -1 : 1;
}
return 0;
}
// compare as string
return x.CompareTo(y);
}
}
Maybe you could just string compare it?
I'm surprised that Double.Parse doesn't throw an exception with those numbers with more than one decimal place.
You really need to write some rules about how to compare these strings.
I would split the strings using String.Split() on the dot character, then iterate through the two lists created and as soon as one of the levels contained a lower or higher number than the other, or if you ran out of items in one of the lists then you wold return 1 or -1 as appropriate. If you get to the end of both lists in the same iteration of the loop then they are the same and return 0.
I would write the code but I don't have VS in front of me.