0

I'm working on a computing probabilities of winning in a poker (texas hold'em) game. And for that I have to make a function that returns every combination of 5 cards possible from the two cards of the hand and the 3 or 4 or 5 cards on the table. I thought about doing a match on the number of cards on the table. So if I have 3, then the only set of five cards is the two in hand + the 3 on the table, but once I have 4 or 5 cards on my table I will be having from 6 to 21 combinations possible so I started this way

let compute_comb (d:donne) (t:table) =
  let l = listTable t in
  let l_size = List.length l in
  match l_size with
  |3 -> listCartes d t
  |4 -> 

note that donne is a type defined like this type donne = card*card and table is defined like this type table = card*card*card*card*card

vonaka
  • 913
  • 1
  • 11
  • 23

1 Answers1

0

In my opinion, this is a typical example of problem in which considering a more general case makes it easier. Consider the problem of finding all combinaisons of n cards in a hand of l cards.


For the sake of simplicity, I'll consider that cards are just generic 'a. Also, I won't make any difference between the hand and the table, I just consider both as a single list. Separating both could lead to better solutions, but make it less simple to understand :-)


So, you'll have a function comb n l which returns a list of all the combinations of n elements in the list l (hence comb returns a 'a list list). Let's do it recursively:

First, if n is greater than the length of l, just give up:

exception NotEnoughElement of int*int
let rec comb n l = 
let length_l = List.length l in
if n > length_l
  raise (NotEnoughElement (n, length_l))
else

Now we are sure that n is suitable, there are 3 cases to consider depending on n: if n = 0, then returns an empty list

match n with
| 0 -> []

if n is the size of the list, then there is no choice: the only suitable sublist is... the list itself (this is similar in your case when you have cards on the table). Notice that we return a list containing l to fulfill our agreement that comb returns a list of all sublist.

| _ when n == length_l -> [l]

finally, if n is smaller than the length of l, we have a choice to make: either we take the head of l, either we don't.

| _ -> 

If we take the head of l, then we have to search for combination of n-1 elements in the tail of l, and we append the head of l to all those subcombinations. To do the appending, take this function

  let app_head sublist = (List.hd l) :: sublist in

How to take the combination of n-1 elements in the tail of l ? Well, we have aggrement saying that comb n l returns the list of all combination of size n in l, so we can use this "contract":

  let sublists = comb (n-1) (List.tl l) in

Now, let's do the appending, the List module provides a map function which applies a function to all elements of the list, we can use our app_head function:

  let combination_head_taken = List.map app_head sublists in

Now, if we don't take the head, then we still have to search for n elements in the tail of l. Once again, we use our aggrement on comb:

  let combination_head_not_taken = comb (n-1) (List.tl l) in

And then, just concatenate combinations generated in the two subcases:

  combination_head_taken @ combination_head_not_taken

You can then play with utop (assuming you wrote this function in comb.ml):

$ utop
# #use "comb.ml";;
# let hand = [1;2;3;4;5];;
# comb 3 hand;;
- : int list list = [[2; 3; 4; 5]; [1; 3; 4; 5]; [1; 2; 4; 5]; [1; 2; 3; 5]]
Bromind
  • 1,065
  • 8
  • 23