I am trying to write a poker hand evaluation method in c#. I have managed to do this for every poker hand using linq except a straight. For those that don't play a straight is made up of 5 cards with increments of 1 for each card. Ace can be high or low.
I have created an object called card which has a suit, rank and value (J = 11, Q =12 etc..). My method will be passed a list of this object containing 7 cards (hole cards and the board.)
Another thing to bear in mind is that a straight can only be made if the player has a 5 or 10.
See below my methods for other poker hands and please let me know if you have an idea for the straight method. Pseudo code would be fine also.
public bool CheckPair(List<Card> cards)
{
//see if exactly 2 cards card the same rank.
return cards.GroupBy(card => card.Rank).Count(group => group.Count() == 2) == 1;
}
public bool CheckTwoPair(List<Card> cards)
{
//see if there are 2 lots of exactly 2 cards card the same rank.
return cards.GroupBy(card => card.Rank).Count(group => group.Count() >= 2) == 2;
}
public bool CheckTrips(List<Card> cards)
{
//see if exactly 3 cards card the same rank.
return cards.GroupBy(card => card.Rank).Any(group => group.Count() == 3);
}
public bool CheckStraight(List<Card> cards)
{
// order by decending to see order
var cardsInOrder = cards.OrderByDescending(a => a.Value).ToList();
// check for ace as can be high and low
if (cardsInOrder.First().Rank == "A")
{
// check if straight with ace has has 2 values
bool highStraight = cards.Where(a => a.Rank == "K" || a.Rank == "Q" || a.Rank == "J" || a.Rank == "10").Count() == 4;
bool lowStraight = cards.Where(a => a.Rank == "2" || a.Rank == "3" || a.Rank == "4" || a.Rank == "5").Count() == 4;
// return true if straight with ace
if (lowStraight == true || highStraight == true)
{
return true;
}
}
else
{
// check for straight here
return true;
}
// no straight if reached here.
return false;
}
public bool CheckFlush(List<Card> cards)
{
//see if 5 or more cards card the same rank.
return cards.GroupBy(card => card.Suit).Count(group => group.Count() >= 5) == 1;
}
public bool CheckFullHouse(List<Card> cards)
{
// check if trips and pair is true
return CheckPair(cards) && CheckTrips(cards);
}
public bool CheckQuads(List<Card> cards)
{
//see if exactly 4 cards card the same rank.
return cards.GroupBy(card => card.Rank).Any(group => group.Count() == 4);
}
// need to check same 5 cards
public bool CheckStraightFlush(List<Card> cards)
{
// check if flush and straight are true.
return CheckFlush(cards) && CheckStraight(cards);
}
This might not be the best performing check, but I'd say it's very readable which is usually a good property.
Just grab 5 cards, skipping cards you've already seen every iteration and check for a straight for each sequence. An ordered sequence is a straight if it does not contain doubles and if the first and last cards difference is 5.
public bool CheckStraight(List<Card> cards)
{
//maybe check 5 and 10 here first for performance
var ordered = cards.OrderByDescending(a => a.Value).ToList();
for(i = 0; i < ordered.Count - 5; i++) {
var skipped = ordered.Skip(i);
var possibleStraight = skipped.Take(5);
if(IsStraight(possibleStraight)) {
return true;
}
}
return false;
}
public bool IsStraight(List<Card> fiveOrderedCards) {
var doubles = cards.GroupBy(card => card.Rank).Count(group => group.Count() > 1);
var inARow = cards[4] - cards[0] = 5; //Ace is 0
return !doubles && inARow;
}
I have made some small changes to Glubus answer. The code below does the job however you will have to check manually for a wheel (A,1,2,3,4,5) straight.
public bool CheckStraight(List<Card> cards)
{
//maybe check 5 and 10 here first for performance
var ordered = cards.OrderByDescending(a => a.Value).ToList();
for (var i = 0; i < ordered.Count - 4; i++)
{
var skipped = ordered.Skip(i);
var possibleStraight = skipped.Take(5).ToList();
if (IsStraight(possibleStraight))
{
return true;
}
}
return false;
}
public bool IsStraight(List<Card> cards)
{
return cards.GroupBy(card => card.Value).Count() == cards.Count() && cards.Max(card => (int)card.Value) - cards.Min(card => (int)card.Value) == 4;
}
erm,
function bool IsStraight(IEnumerable<int> cards)
{
var orderedCards = cards.OrderBy(n => n).ToList();
var test = orderdCards.Zip(orderdCards.Skip(1), (a, b) => b - a);
var count = 0;
foreach(var n in test)
{
if (n == 1)
{
count++;
if (count == 4)
{
return true;
}
}
else
{
count = 0;
}
}
return false;
}
I cannot think about real one liner, since A can be 1 or 14, but this should be good:
int c = 5; // How many cards straight
bool Ais1 = cards.OrderBy(a => a.Value).Select((i,j) => i.Value-j).Distinct().Skip(1).Count() <= (cards.Count - c);
bool Ais14 = cards.OrderBy(a => (a.Value == 1 ? 14 : a.Value)).Select((i,j) => (i.Value == 1 ? 14 : i.Value)-j).Distinct().Skip(1).Count() <= (cards.Count - c);
return Ais1 || Ais14;
(Updated - thank you Janne, I've fixed the code)
来源:https://stackoverflow.com/questions/39637965/c-sharp-check-for-a-poker-straight