I'm developing a poker game in C#. At the moment I'm trying to get the players hand score using RegEx. I search the string (composed of the cards suit and number) and look for suits or numbers to match the RegEx. If i get 2 matches then the player has a pair, 3 matches he has 3 of a kind.
I have 3 classes at the moment, a Card class (with number and suit), a Deck class (that contains 52 Cards) and a Hand class that gets five cards from the shuffled deck.
Deck class has a shuffleDeck();
Hand class has the functions to calculate the score (is in these functions that I am using RegEx).
I generate the string on which I use RegEx by adding the 5 suits and numbers that the hand has.
Is this a good idea or should I do it another way, if so, how?
Thank you for your help
PS. I am one of the unexperienced programmers that want to use a newly learned tool for everything
I do not think that a regex is the appropriate way to deal with this. You probably should be using a more sophisticated representation of a hand than a string.
You have not provided much detail, but what from what I have read, I assume you're not pushing the OOP very far...
I would have a Card class that has a Rank and Suit class instances. I would then have a deck class that handles shuffling / dealing...
I would then have a Hand class that would contain your poker hand of n Card objects...
In this way you can build up rules to evaluate each hand object, thus being more flexible and more extensible in the future...say if you want to make another card game / add support for another variant of poker...
Using Regular expressions to do all of this seems to be a pretty poor choice.
I would agree with the others, that Regex seems like a bad choice. It might work with pairs, 3 of a kind, 4 of a kind. However, it might get kind of tricky (or impossible) once you start looking at hands like flushes, straights, and 2 pair.
I think the best solution would be to evaluate the cards from best hand to worst hand, as shown here, and as soon as your find a match, then that is your hand. This ensures that you don't mistake 4 of a kind for 2 pair. Or a straight flush for just a straight, or just a flush. I would go with mmattax and create an object for the card, and an object for the hand, then you can evaluate the cards in each hand to see if they meet the required criteria for each hand.
I think prime numbers are a good solution for that.
consider :
// D H S C
colors = [7,5,3,2]
// A Q K J T 9 8 7 6 5 4 3 2
ranks = [61,59,53,43,41,37,31,29,23,19,17,13,11,61]
a unique card is identified by a color prime number * a rank prime number.
(for example, As of Diamonds : prime = 7 * 61)
so an entiere unique deck or combinaison are identified by prime * prime * prime * prime * prime
if there is a flush of Diamonds, the 5 cards deck's primes ID must by divisble ( mod = 0 ) by the flush of diamonds ID ( 7 ^ 5 because diamonds color prime is 7 )
Using a string to represent the hand seems like a poor decision. My recommendation would be to use an Enum to represent the Suit and another to represent the numeric value of the card.
Related
I want to write a lottery draw program which needs to randomly choose 20000 numbers from 1-2000000 range. The code is as below:
Random r = New Random(seed); //seed is a 6 digits e.g 123456
int i=0;
while(true){
r.Next(2000000);
i++;
if(i>=20000)
break;
}
My questions are:
Can it make sure the same possibility of all the numbers from 1 to 2000000?
Is the upper bound 2000000 included in the r.Next()?
Any suggestion?
The .NET Random class does a fairly good job of generating random numbers. However be aware that if you seed it with the same number you'll get the same "random" numbers each time. If you don't want this behavior don't provide a seed.
If you're after much more random number generator than the built in .NET one then take a look at random.org. It's one of the best sites out there for getting true random numbers - I believe there's an API. Here's a quote from their site:
RANDOM.ORG offers true random numbers to anyone on the Internet. The
randomness comes from atmospheric noise, which for many purposes is
better than the pseudo-random number algorithms typically used in
computer programs. People use RANDOM.ORG for holding drawings,
lotteries and sweepstakes, to drive games and gambling sites, for
scientific applications and for art and music. The service has existed
since 1998 and was built by Dr Mads Haahr of the School of Computer
Science and Statistics at Trinity College, Dublin in Ireland. Today,
RANDOM.ORG is operated by Randomness and Integrity Services Ltd.
Finally Random.Next() is exlusive so the upper value you supply will never be called. You may need to adjust your code appropriately if you want 2000000 to be in there.
It includes the minValue but does not include the maxValue. Therefore if you want to generate numbers from 1 to 2000000 use:
r.Next(1,2000001)
I believe your question is implementation dependent.
The naïve method of generating a random integer in a range is to generate a random 32-bit word and then normalise it across your range.
The larger the range you're normalising the more the probabilities of each individual value fluctuate.
In your situation, you're normalising 4.3 billion inputs over 2 million outputs. This will mean that the probabilities of each number in your range will differ by up to about 1 in 2000 (or 0.05%). If this slight difference in probabilities is okay for you, then go ahead.
Upperbound included?
No, the upperbound is exclusive so you'll have to use 2000001 to include 2000000.
Any suggestion?
Let me take the liberty of suggesting not to use a while(true) / break. Simply put the condition of the if in your while statement:
Random r = New Random(seed); //seed is a 6 digits e.g 123456
int i=0;
while(i++ < 20000)
{
r.Next(1, 2000001);
}
I know this is nitpicking, but it is a suggestion... :)
For example, i would like to shuffle 4 decks of cards, and make sure:
Any consecutive 4 cards won't come from the same deck.
Surely I can do the shuffling first and then filter out bad permutations, but if the restrictions are strong (e.g. any consecutive 2 cards won't come from the same deck) , there will be too many failures.
If i don't mind that if it is slightly unbiased, (of course the less bias the better), how should I do?
Edit: Clarify
Yes I want as uniformly as possible to pick from all full shuffles such that this additional criterion applied.
I would process as below :
First you can shuffle each 4 decks (using FYK algorithm)
Then generate a 4 partitions (* I define partition below) of your 52 cards of 4 decks with the constraint of having not more than 3 element in each set of the partition :
For example :
(1,3,0,3,2,0,1) would be a partition of 10 with this constraint
(1,1,1,1,1,1,1,1,1,1) would be a partition of 10 too with this constraint
Then Mix the 4 decks based on these partition.
For example if you have :
(3,2,1)
(2,2,2)
you take the 3 first of deck one then 2 of deck 2 then 2 of deck one the 2 of deck 2 then 1 of deck 1 then 2 of deck 2. (okay ?)
All partitions are not valid, so you need to add one more constraint :
for example with this method :
(1,2,1,1,1,1,1,1)
(3,3,3)
will end up having 4 elements of deck 1 at the end.
So the last partition must satisfy a constraint, I wrote a little python program to generate these partitions.
from random import randint,choice
def randomPartition(maxlength=float('inf'),N=52):
'''
the max length is the last constraint in my expanation:
you dont want l[maxlength:len(l)]) to be more than 3
in this case we are going to randomly add +1 to all element in the list that are less than 3
N is the number of element in the partition
'''
l=[] # it's your result partition
while(sum(l)<N ):
if (len(l)>maxlength and sum(l[maxlength:len(l)])>=3): #in the case something goes wrong
availableRange=[i for i in range(len(l)) if l[i]<3] #create the list of available elements to which you can add one
while(sum(l)<N):
temp=choice(availableRange) #randomly pick element in this list
l[temp]+=1
availableRange=[i for i in range(len(l)) if l[i]<3] #actualize the list
if availableRange==[]: #if this list gets empty your program cannot find a solution
print "NO SOLUTION"
break
break
else:
temp=randint(0,min(N-sum(l),3)) # If everything goes well just add the next element in the list until you get a sum of N=52
l.append(temp)
return l
Now you can generate the 4 partitions and mix the decks according to these partitions :
def generate4Partitions():
l1=randomPartition();
l2=randomPartition();
l3=randomPartition();
m=max(len(l1),len(l2),len(l3))
l4=randomPartition(m);
return l1,l2,l3,l4
This 4 partitions will always be admissible based on their definitions.
NOte:
There might be more cases where it's not admissible , for example :
(3,0,0,3)
(0,3,3,0)
I guess this code needs to be modified a bit to take more constraints into account.
But it should be easy, just to delete unwanted zeros,like this:
(3,0,3)
(0,3,3,0)
Hope it's understandable and it helps
I've implemented a Texas Hold'em game using C#.
I wrote classes like Card, Deck, Player, Table etc...
For example:
Player player1 = new Player("player1");
player1.Card1 = new Card(4, Symbol.Clubs, true);
player1.Card2 = new Card(5, Symbol.Clubs, true);
Card card1 = new Card(4, Symbol.Clubs, true);
Card card2 = new Card(7, Symbol.Hearts, true);
Card card3 = new Card(2, Symbol.Spades, true);
Card card4 = new Card(4, Symbol.Diamonds, true);
Card card5 = new Card(4, Symbol.Clubs, true);
Card[] tableCards = {card1, card2, card3, card4, card5};
I've also wrote some methods for evaluate cards array, like IsFlush, IsStraight, IsPair and so on.
My question is how should I pick the best hand combination if I got 7 cards(2 hand, 5 from the table).
In this code example it's {4,4,4,4,7}.
Don't write your code against 5-card hands. Instead, write it in general. So,
ContainsStraightFlush
ContainsFourOfAKind
ContainsFullHouse
etc. would eat a collection of cards and return true if some subset of those cards is a straight flush, four of a kind, etc. respectively.
Then runs backwards from highest ranking hand to lowest. If one of these methods returns true, then you can easily pick off the best hand that satisfies that condition. For example on
2h Kh Qh Jh Th 9h 6c
ContainsStraightFlush would return true, and then you can pick off 9h Th Jh Qh Kh as the best hand.
Start by sorting the cards, it will make doing your search for the best hand that much easier, then you just have to compare adjacent elements for multiples of the same number, or straights. then you just have a special case to look for a flush
The easiest way to do it is make every collection of 5 cards possible and grab the hand value. Remember the best hand. There are only 21 combinations for the 7 card situation, so it's not good in terms of optimality, but it's not terrible either unless you are using this for research.
foreach (possible 5 card combination in allCards)
bestHand = Max(bestHand, GetValue(possible));
Alternatively you could create an array that has 1 entry for each card, and each index is a pointer to new array which has all 2 card combinations, and each index in that is an array for all 3 card combinations, etc. If you work it out with all suit and rank abstractions possible, the total size of the data structure is about 128 MB in memory. There is a reference implementation in c++ on the 2+2 forums.
Don't do it like this, it is awfully slow and actually rather cumbersome to write (the logic is quite hairy). Also, for Monte Carlo simulations where you'll need to run hundred of millions of hands, such an approach simply cannot stand.
See this link for a survey of available techniques. Actually, using table-based comparison algorithms is much simpler to code than using a truckload of if statements.
Most of the routines presented in the above article are available in already-bundled C# libraries that you can plug your code into.
[The first high-performance original idea is there, and uses lookup tables, perfect hashes and a nice trick of multiplying prime numbers to evaluate a hand at a glance.]
create an array of cards, and add the first 5 cards. Then, foreach additional card, find the lowest in the card hand, and see if the extra card is larger, if so, switch them. Keeping in mind that you need to find pairs, straights, and full houses and such
I've got a weird problem to solve - this is to be used in designing a quiz, but it's easiest to explain using teams.
There're 16 teams, and 24 matches. 4 teams play in every match. Each team has to appear once against 12/16 teams and twice against the remaining 3/16, and has to appear exactly 6 times. Any ideas on how to do this? If there's a software that can do this, that'd be great as well.
UPDATE:
I'm not sure if the above is even possible. Here is the minimum we're trying to accomplish:
Number of games is not set.
Each Game has 4 teams.
Each team gets an equal number of games.
Is this possible?
Check this ...
http://en.wikipedia.org/wiki/Round-robin_tournament
I think someone could generalize the algorithm so that applies for more than 2 teams ...
I know this doesn't answer the question but it provides some tip ...
This also may help a little ...
http://en.wikipedia.org/wiki/Tournament_(graph_theory)
Note that each team plays 3 others per match, so it takes at least 5 matches to play all 15 other teams. We hope, then, that there is a solution for 20 matches where each team plays 5 matches and plays each team exactly once.
With 16 teams it's possible to construct a solution by hand in the following way...
Divide the 20 matches into 5 rounds
Number the teams 1 to 16
For each match in turn, for each of the 4 places in that match, allocate the first team which
is still available to play in that round
has not yet played any of the teams already allocated to that match
You can narrow the search for available teams somewhat by noting that each match must contain exactly one team from each match of the previous round, so for place n you need only consider the teams which played match n in the previous round.
If we want 24 matches then any random choice of matches will suffice in the sixth round to fit the original requirements. However, to also ensure that no exact matches are repeated we can switch pairs of teams between the matches in some previous round. That is, if {1,2,3,4} and {5,6,7,8} were matches in some round then in round 6 we'll have {1,2,7,8} and {3,4,5,6}. Since 1 and 2 played each other exactly once in rounds 1-5, in the match {1,2,3,4}, we certainly haven't played match {1,2,7,8} yet.
The choice of data structures to implement that efficiently is left as an exercise for the reader.
Pull out your combinatorics book. I remember these questions as in that scope.
"Combinatorial Designs and Tournaments" was a textbook I had for a course about Combinatorial Designs that had this type of problem. One of my majors back in university was Combinatorics & Optimization, so I do remember a little about this kind of thing.
A little more clarity identifying the problem would be helpful. What type of sport are you trying to schedule. It sounds like you're into a 16 person tennis league and each week 4 individuals players show up on four courts to play a doubles match (players A&B vs C&D). The same is happening on the other three courts with players E thru P. Is this what you're looking for? If so the answer is easy. If not, I still don't understand what you're looking for.
I have a collection of structures. Each structure has 2 keys. If I query using key #1, I should get key #2 in return and vice versa.
It's easy to write code on the desktop when you have the power of the .NET Framework behind you. I am writing code in the .NET Micro Framework, which is a very very limited subset of framework. For instance, as far as collections, I only have arrays and ArrayList objects at my disposal.
So for example here is the list of structures:
Key #1 Key #2
6 A
7 F
8 Z
9 B
So when I query for 8, I should get Z.
When I query for Z, I should get 8.
I am looking to do the fastest and least processor intensive lookup using either arrays or ArrayList. The device I am coding against is a low-end ARM processor, thus I need to optimize early.
If the set is fixed, look into perfect hash functions.
Any reason you can't write your own hashmap?
It depends on the number of entries and your access pattern.
Given that your access pattern is random access if you don't have too many elements you could have 2 Arrays of Pairs and then use
Array.BinarySearch()
Well... if you want the fastest and aren't too concerned about memory, just use two hash tables. One going one way, one going to other. Not sure if there's a more memory efficient way...
Or use just one hash table but have the entries for both directions in there.
Is it not as simple as :
find the key in the array you're querying
return the key at the same index in the opposite array
I would keep it as simple as possible and just iterate through the array you're searching. You'll probably only see a benefit from implementing some hashing routines if your list is (plucks figure from air) over 1k+ elements, with the added complexity of your own hashing routines slowing things down somewhat.
Several solutions:
Keep 2 lists in sync, do a linear search. Works well unless your collections are very large, or you're searching repeatedly.
Two hashtables. Writing your own is fairly easy -- it is just a fixed array of buckets (each bucket can be an ArrayList). Map an item to a bucket by doing object.GetHashCode() % numBuckets.
Two arrays the size of the range of values. If your numbers are in a fixed range, allocate an array the size of the range, with elements being items from the other group. Super quick and easy, but uses a lot of memory.
If it's a fixed set, consider using switch. See the answer to a similar question here.
I had this problem several years ago when programming C, that we need to find a barcode (numeric) quickly in about 10 thousand rows (in that time, using a file as the Database - as it was a hand device)
I created my own search that instead of iterate one by one would start always in the middle...
searching for 4050 in 10000 item stack
start on 5000 ( 10 000 / 2 )
now, is the number higher or lower ... lower
start on 2500 ( 5000 / 2 )
now, is the number higher or lower ... higher
start on 3750 ( 2500 + 2500 / 2 )
now, is the number higher or lower ... higher
start on 4375 ( 3750 + 1250 / 2 )
now, is the number higher or lower ... lower
start on 4063 ( 4375 - 625 / 2 )
now, is the number higher or lower ... lower
start on 3907 ( 4063 - 312 / 2 )
now, is the number higher or lower ... higher
start on 3907 ( 3907 + 156 / 2 )
now, is the number higher or lower ... higher
start on 3946 ( 3907 + 78 / 2 )
now, is the number higher or lower ... higher
...
until you get the value... you will need to search about 14 times instead 4050 iterations
about the letters ... they all represent a numeric number as well...
Hope it helps