I am trying to generate a text file of distinct 5-card poker hands, very similar to this question (which I actually posted an answer to). The program I pieced together from this answer to that question mostly works. However, there are two major problems: The number of hands is incorrect, and every hand has the 2 of Hearts in it. Perhaps if the number of hands was correct, the hands would be correct as well.
The person that posted the answer I was working from stated that he got the correct number by not seeding the initial card. However, if you remove the seed you get an Invalid Exception error when it tries to do the ranking down the line. Seeding it makes the program work, but returns only half of the hands.
What do I need to do to this code to get all distinct 5 card poker hands?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace PokerHands
{
struct Card
{
public int Suit { get; set; }
public int Rank { get; set; }
}
class Hand
{
public List<Card> Cards { get; set; }
public string HandString { get; set; }
}
class Program
{
static int ranks = 13;
static int suits = 4;
static int cardsInHand = 5;
static List<Hand> possibleHands = new List<Hand>();
static void Main(string[] args)
{
List<Card> cards = new List<Card>();
cards.Add(new Card() { Rank = 0, Suit = 0 });
int numHands = GenerateAllHands(cards);
int counter = 0;
Console.WriteLine(numHands);
Console.WriteLine(possibleHands.Count);
possibleHands.Shuffle();
using (System.IO.StreamWriter file = new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "Hands.txt"))
{
foreach (Hand hand in possibleHands)
{
counter += 1;
hand.Cards.Shuffle();
foreach (Card card in hand.Cards)
{
hand.HandString += GetCardName(card) + " ";
}
file.WriteLine(hand.HandString.Trim());
}
}
Console.ReadLine();
}
static string GetCardName(Card card)
{
string cardName;
string cardFace;
string cardSuit;
switch (card.Rank)
{
case 0:
cardFace = "2";
break;
case 1:
cardFace = "3";
break;
case 2:
cardFace = "4";
break;
case 3:
cardFace = "5";
break;
case 4:
cardFace = "6";
break;
case 5:
cardFace = "7";
break;
case 6:
cardFace = "8";
break;
case 7:
cardFace = "9";
break;
case 8:
cardFace = "10";
break;
case 9:
cardFace = "J";
break;
case 10:
cardFace = "Q";
break;
case 11:
cardFace = "K";
break;
default:
cardFace = "A";
break;
}
switch (card.Suit)
{
case 0:
cardSuit = "H";
break;
case 1:
cardSuit = "D";
break;
case 2:
cardSuit = "S";
break;
default:
cardSuit = "C";
break;
}
cardName = cardFace + cardSuit;
return cardName;
}
static int GenerateAllHands(List<Card> cards)
{
if (cards.Count == cardsInHand)
{
Hand hand = new Hand();
hand.Cards = cards;
possibleHands.Add(hand);
return 1;
}
List<Card> possibleNextCards = GetPossibleNextCards(cards);
int numSubHands = 0;
foreach (Card card in possibleNextCards)
{
List<Card> possibleNextHand = cards.ToList(); // copy list
possibleNextHand.Add(card);
numSubHands += GenerateAllHands(possibleNextHand);
}
return numSubHands;
}
static List<Card> GetPossibleNextCards(List<Card> hand)
{
int maxRank = hand.Max(x => x.Rank);
List<Card> result = new List<Card>();
// only use ranks >= max
for (int rank = maxRank; rank < ranks; rank++)
{
List<int> suits = GetPossibleSuitsForRank(hand, rank);
var possibleNextCards = suits.Select(x => new Card { Rank = rank, Suit = x });
result.AddRange(possibleNextCards);
}
return result;
}
static List<int> GetPossibleSuitsForRank(List<Card> hand, int rank)
{
int maxSuit = hand.Max(x => x.Suit);
// select number of ranks of different suits
int[][] card = GetArray(hand, rank);
for (int i = 0; i < suits; i++)
{
card[i][rank] = 0;
}
int[][] handRep = GetArray(hand, rank);
// get distinct rank sets, then find which ranks they correspond to
IEnumerable<int[]> distincts = card.Distinct(new IntArrayComparer());
List<int> possibleSuits = new List<int>();
foreach (int[] row in distincts)
{
for (int i = 0; i < suits; i++)
{
if (IntArrayComparer.Compare(row, handRep[i]))
{
possibleSuits.Add(i);
break;
}
}
}
return possibleSuits;
}
class IntArrayComparer : IEqualityComparer<int[]>
{
#region IEqualityComparer<int[]> Members
public static bool Compare(int[] x, int[] y)
{
for (int i = 0; i < x.Length; i++)
{
if (x[i] != y[i]) return false;
}
return true;
}
public bool Equals(int[] x, int[] y)
{
return Compare(x, y);
}
public int GetHashCode(int[] obj)
{
return 0;
}
#endregion
}
static int[][] GetArray(List<Card> hand, int rank)
{
int[][] cards = new int[suits][];
for (int i = 0; i < suits; i++)
{
cards[i] = new int[ranks];
}
foreach (Card card in hand)
{
cards[card.Suit][card.Rank] = 1;
}
return cards;
}
}
public static class ThreadSafeRandom
{
[ThreadStatic]
private static Random Local;
public static Random ThisThreadsRandom
{
get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
}
}
static class MyExtensions
{
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
}
Change the start of GetPossibleNextCards()
to:
static List<Card> GetPossibleNextCards(List<Card> hand)
{
int maxRank = (hand.Count == 0) ? 0 : hand.Max(x => x.Rank);
And remove the first line of GetPossibleSuitsForRank()
, because you are not using the result. i.e. remove this line:
int maxSuit = hand.Max(x => x.Suit); // remove this
And also remove the line in Main()
which is adding the 2H:
cards.Add(new Card() { Rank = 0, Suit = 0 }); // remove this